From 4e3b8e37a34c9b6678320e6fcdad686fb481a58f Mon Sep 17 00:00:00 2001
From: Lokesh Mandvekar <lsm5@fedoraproject.org>
Date: Thu, 30 Apr 2015 10:35:34 -0400
Subject: [PATCH] include updated go-md2man and deps
Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org>
---
.../src/github.com/cpuguy83/go-md2man/LICENSE.md | 21 +
vendor/src/github.com/cpuguy83/go-md2man/README.md | 11 +
.../github.com/cpuguy83/go-md2man/go-md2man.1.md | 21 +
.../github.com/cpuguy83/go-md2man/mangen/mangen.go | 272 ++++
vendor/src/github.com/cpuguy83/go-md2man/md2man.go | 55 +
.../github.com/russross/blackfriday/.travis.yml | 17 +
.../github.com/russross/blackfriday/LICENSE.txt | 29 +
.../src/github.com/russross/blackfriday/README.md | 246 ++++
.../src/github.com/russross/blackfriday/block.go | 1339 ++++++++++++++++++++
.../github.com/russross/blackfriday/block_test.go | 1296 +++++++++++++++++++
vendor/src/github.com/russross/blackfriday/html.go | 922 ++++++++++++++
.../src/github.com/russross/blackfriday/inline.go | 1096 ++++++++++++++++
.../github.com/russross/blackfriday/inline_test.go | 958 ++++++++++++++
.../src/github.com/russross/blackfriday/latex.go | 332 +++++
.../github.com/russross/blackfriday/markdown.go | 838 ++++++++++++
.../github.com/russross/blackfriday/ref_test.go | 128 ++
.../github.com/russross/blackfriday/smartypants.go | 398 ++++++
.../testdata/Amps and angle encoding.html | 17 +
.../testdata/Amps and angle encoding.text | 21 +
.../russross/blackfriday/testdata/Auto links.html | 18 +
.../russross/blackfriday/testdata/Auto links.text | 13 +
.../blackfriday/testdata/Backslash escapes.html | 123 ++
.../blackfriday/testdata/Backslash escapes.text | 126 ++
.../testdata/Blockquotes with code blocks.html | 15 +
.../testdata/Blockquotes with code blocks.text | 11 +
.../russross/blackfriday/testdata/Code Blocks.html | 18 +
.../russross/blackfriday/testdata/Code Blocks.text | 14 +
.../russross/blackfriday/testdata/Code Spans.html | 5 +
.../russross/blackfriday/testdata/Code Spans.text | 6 +
...list-like lines no empty line before block.html | 14 +
...list-like lines no empty line before block.text | 8 +
...rd-wrapped paragraphs with list-like lines.html | 8 +
...rd-wrapped paragraphs with list-like lines.text | 8 +
.../blackfriday/testdata/Horizontal rules.html | 71 ++
.../blackfriday/testdata/Horizontal rules.text | 67 +
.../testdata/Inline HTML (Advanced).html | 15 +
.../testdata/Inline HTML (Advanced).text | 15 +
.../blackfriday/testdata/Inline HTML (Simple).html | 72 ++
.../blackfriday/testdata/Inline HTML (Simple).text | 69 +
.../blackfriday/testdata/Inline HTML comments.html | 13 +
.../blackfriday/testdata/Inline HTML comments.text | 13 +
.../blackfriday/testdata/Links, inline style.html | 11 +
.../blackfriday/testdata/Links, inline style.text | 12 +
.../testdata/Links, reference style.html | 52 +
.../testdata/Links, reference style.text | 71 ++
.../testdata/Links, shortcut references.html | 9 +
.../testdata/Links, shortcut references.text | 20 +
.../testdata/Literal quotes in titles.html | 3 +
.../testdata/Literal quotes in titles.text | 7 +
.../testdata/Markdown Documentation - Basics.html | 314 +++++
.../testdata/Markdown Documentation - Basics.text | 306 +++++
.../testdata/Markdown Documentation - Syntax.html | 946 ++++++++++++++
.../testdata/Markdown Documentation - Syntax.text | 888 +++++++++++++
.../blackfriday/testdata/Nested blockquotes.html | 9 +
.../blackfriday/testdata/Nested blockquotes.text | 5 +
.../testdata/Ordered and unordered lists.html | 166 +++
.../testdata/Ordered and unordered lists.text | 131 ++
.../testdata/Strong and em together.html | 7 +
.../testdata/Strong and em together.text | 7 +
.../russross/blackfriday/testdata/Tabs.html | 26 +
.../russross/blackfriday/testdata/Tabs.text | 21 +
.../russross/blackfriday/testdata/Tidyness.html | 9 +
.../russross/blackfriday/testdata/Tidyness.text | 5 +
.../shurcooL/sanitized_anchor_name/.travis.yml | 10 +
.../shurcooL/sanitized_anchor_name/README.md | 25 +
.../shurcooL/sanitized_anchor_name/main.go | 29 +
.../shurcooL/sanitized_anchor_name/main_test.go | 35 +
67 files changed, 11863 insertions(+)
create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md
create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/README.md
create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md
create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go
create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/md2man.go
create mode 100644 vendor/src/github.com/russross/blackfriday/.travis.yml
create mode 100644 vendor/src/github.com/russross/blackfriday/LICENSE.txt
create mode 100644 vendor/src/github.com/russross/blackfriday/README.md
create mode 100644 vendor/src/github.com/russross/blackfriday/block.go
create mode 100644 vendor/src/github.com/russross/blackfriday/block_test.go
create mode 100644 vendor/src/github.com/russross/blackfriday/html.go
create mode 100644 vendor/src/github.com/russross/blackfriday/inline.go
create mode 100644 vendor/src/github.com/russross/blackfriday/inline_test.go
create mode 100644 vendor/src/github.com/russross/blackfriday/latex.go
create mode 100644 vendor/src/github.com/russross/blackfriday/markdown.go
create mode 100644 vendor/src/github.com/russross/blackfriday/ref_test.go
create mode 100644 vendor/src/github.com/russross/blackfriday/smartypants.go
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Auto links.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Auto links.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tabs.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tabs.text
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html
create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text
create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml
create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md
create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go
create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go
diff --git a/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md b/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md
new file mode 100644
index 0000000..1cade6c
--- /dev/null
+++ b/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Brian Goff
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/src/github.com/cpuguy83/go-md2man/README.md b/vendor/src/github.com/cpuguy83/go-md2man/README.md
new file mode 100644
index 0000000..8eb4b2e
--- /dev/null
+++ b/vendor/src/github.com/cpuguy83/go-md2man/README.md
@@ -0,0 +1,11 @@
+go-md2man
+=========
+
+** Work in Progress **
+This still needs a lot of help to be complete, or even usable!
+
+Uses blackfriday to process markdown into man pages.
+
+### Usage
+
+./md2man -in /path/to/markdownfile.md -out /manfile/output/path
diff --git a/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md b/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md
new file mode 100644
index 0000000..1f7096a
--- /dev/null
+++ b/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md
@@ -0,0 +1,21 @@
+go-md2man 1 "January 2015" go-md2man "User Manual"
+==================================================
+
+# NAME
+ go-md2man - Convert mardown files into manpages
+
+# SYNOPSIS
+ go-md2man -in=[/path/to/md/file] -out=[/path/to/output]
+
+# Description
+ go-md2man converts standard markdown formatted documents into manpages. It is
+ written purely in Go so as to reduce dependencies on 3rd party libs.
+
+# Example
+ Convert the markdown file "go-md2man.1.md" into a manpage.
+
+ go-md2man -in=README.md -out=go-md2man.1.out
+
+# HISTORY
+ January 2015, Originally compiled by Brian Goff( cpuguy83@gmail.com )
+
diff --git a/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go b/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go
new file mode 100644
index 0000000..d436eed
--- /dev/null
+++ b/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go
@@ -0,0 +1,272 @@
+package mangen
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ "github.com/russross/blackfriday"
+)
+
+type Man struct{}
+
+func ManRenderer(flags int) blackfriday.Renderer {
+ return &Man{}
+}
+
+func (m *Man) GetFlags() int {
+ return 0
+}
+
+func (m *Man) TitleBlock(out *bytes.Buffer, text []byte) {
+ out.WriteString(".TH ")
+
+ splitText := bytes.Split(text, []byte("\n"))
+ for i, line := range splitText {
+ line = bytes.TrimPrefix(line, []byte("% "))
+ if i == 0 {
+ line = bytes.Replace(line, []byte("("), []byte("\" \""), 1)
+ line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1)
+ }
+ line = append([]byte("\""), line...)
+ line = append(line, []byte("\" ")...)
+ out.Write(line)
+ }
+
+ out.WriteString(" \"\"\n")
+}
+
+func (m *Man) BlockCode(out *bytes.Buffer, text []byte, lang string) {
+ out.WriteString("\n.PP\n.RS\n\n.nf\n")
+ escapeSpecialChars(out, text)
+ out.WriteString("\n.fi\n.RE\n")
+}
+
+func (m *Man) BlockQuote(out *bytes.Buffer, text []byte) {
+ out.WriteString("\n.PP\n.RS\n")
+ out.Write(text)
+ out.WriteString("\n.RE\n")
+}
+
+func (m *Man) BlockHtml(out *bytes.Buffer, text []byte) {
+ fmt.Errorf("man: BlockHtml not supported")
+ out.Write(text)
+}
+
+func (m *Man) Header(out *bytes.Buffer, text func() bool, level int, id string) {
+ marker := out.Len()
+
+ switch {
+ case marker == 0:
+ // This is the doc header
+ out.WriteString(".TH ")
+ case level == 1:
+ out.WriteString("\n\n.SH ")
+ case level == 2:
+ out.WriteString("\n.SH ")
+ default:
+ out.WriteString("\n.SS ")
+ }
+
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+}
+
+func (m *Man) HRule(out *bytes.Buffer) {
+ out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n")
+}
+
+func (m *Man) List(out *bytes.Buffer, text func() bool, flags int) {
+ marker := out.Len()
+ out.WriteString(".IP ")
+ if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
+ out.WriteString("\\(bu 2")
+ } else {
+ out.WriteString("\\n+[step" + string(flags) + "]")
+ }
+ out.WriteString("\n")
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+
+}
+
+func (m *Man) ListItem(out *bytes.Buffer, text []byte, flags int) {
+ out.WriteString("\n\\item ")
+ out.Write(text)
+}
+
+func (m *Man) Paragraph(out *bytes.Buffer, text func() bool) {
+ marker := out.Len()
+ out.WriteString("\n.PP\n")
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ if marker != 0 {
+ out.WriteString("\n")
+ }
+}
+
+// TODO: This might now work
+func (m *Man) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
+ out.WriteString(".TS\nallbox;\n")
+
+ out.Write(header)
+ out.Write(body)
+ out.WriteString("\n.TE\n")
+}
+
+func (m *Man) TableRow(out *bytes.Buffer, text []byte) {
+ if out.Len() > 0 {
+ out.WriteString("\n")
+ }
+ out.Write(text)
+ out.WriteString("\n")
+}
+
+func (m *Man) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
+ if out.Len() > 0 {
+ out.WriteString(" ")
+ }
+ out.Write(text)
+ out.WriteString(" ")
+}
+
+// TODO: This is probably broken
+func (m *Man) TableCell(out *bytes.Buffer, text []byte, align int) {
+ if out.Len() > 0 {
+ out.WriteString("\t")
+ }
+ out.Write(text)
+ out.WriteString("\t")
+}
+
+func (m *Man) Footnotes(out *bytes.Buffer, text func() bool) {
+
+}
+
+func (m *Man) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
+
+}
+
+func (m *Man) AutoLink(out *bytes.Buffer, link []byte, kind int) {
+ out.WriteString("\n\\[la]")
+ out.Write(link)
+ out.WriteString("\\[ra]")
+}
+
+func (m *Man) CodeSpan(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\fB\\fC")
+ escapeSpecialChars(out, text)
+ out.WriteString("\\fR")
+}
+
+func (m *Man) DoubleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\fB")
+ out.Write(text)
+ out.WriteString("\\fP")
+}
+
+func (m *Man) Emphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\fI")
+ out.Write(text)
+ out.WriteString("\\fP")
+}
+
+func (m *Man) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
+ fmt.Errorf("man: Image not supported")
+}
+
+func (m *Man) LineBreak(out *bytes.Buffer) {
+ out.WriteString("\n.br\n")
+}
+
+func (m *Man) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
+ m.AutoLink(out, link, 0)
+}
+
+func (m *Man) RawHtmlTag(out *bytes.Buffer, tag []byte) {
+ out.Write(tag)
+}
+
+func (m *Man) TripleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\s+2")
+ out.Write(text)
+ out.WriteString("\\s-2")
+}
+
+func (m *Man) StrikeThrough(out *bytes.Buffer, text []byte) {
+ fmt.Errorf("man: strikethrough not supported")
+}
+
+func (m *Man) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
+
+}
+
+func (m *Man) Entity(out *bytes.Buffer, entity []byte) {
+ // TODO: convert this into a unicode character or something
+ out.Write(entity)
+}
+
+func processFooterText(text []byte) []byte {
+ text = bytes.TrimPrefix(text, []byte("% "))
+ newText := []byte{}
+ textArr := strings.Split(string(text), ") ")
+
+ for i, w := range textArr {
+ if i == 0 {
+ w = strings.Replace(w, "(", "\" \"", 1)
+ w = fmt.Sprintf("\"%s\"", w)
+ } else {
+ w = fmt.Sprintf(" \"%s\"", w)
+ }
+ newText = append(newText, []byte(w)...)
+ }
+ newText = append(newText, []byte(" \"\"")...)
+
+ return newText
+}
+
+func (m *Man) NormalText(out *bytes.Buffer, text []byte) {
+ escapeSpecialChars(out, text)
+}
+
+func (m *Man) DocumentHeader(out *bytes.Buffer) {
+}
+
+func (m *Man) DocumentFooter(out *bytes.Buffer) {
+}
+
+func needsBackslash(c byte) bool {
+ for _, r := range []byte("-_{}&\\~") {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+func escapeSpecialChars(out *bytes.Buffer, text []byte) {
+ for i := 0; i < len(text); i++ {
+ // directly copy normal characters
+ org := i
+
+ for i < len(text) && !needsBackslash(text[i]) {
+ i++
+ }
+ if i > org {
+ out.Write(text[org:i])
+ }
+
+ // escape a character
+ if i >= len(text) {
+ break
+ }
+ out.WriteByte('\\')
+ out.WriteByte(text[i])
+ }
+}
diff --git a/vendor/src/github.com/cpuguy83/go-md2man/md2man.go b/vendor/src/github.com/cpuguy83/go-md2man/md2man.go
new file mode 100644
index 0000000..f8b1722
--- /dev/null
+++ b/vendor/src/github.com/cpuguy83/go-md2man/md2man.go
@@ -0,0 +1,55 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "github.com/cpuguy83/go-md2man/mangen"
+ "github.com/russross/blackfriday"
+)
+
+var inFilePath = flag.String("in", "", "Path to file to be processed")
+var outFilePath = flag.String("out", "", "Path to output processed file")
+
+func main() {
+ flag.Parse()
+
+ inFile, err := os.Open(*inFilePath)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ defer inFile.Close()
+
+ doc, err := ioutil.ReadAll(inFile)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+
+ renderer := mangen.ManRenderer(0)
+ extensions := 0
+ extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS
+ extensions |= blackfriday.EXTENSION_TABLES
+ extensions |= blackfriday.EXTENSION_FENCED_CODE
+ extensions |= blackfriday.EXTENSION_AUTOLINK
+ extensions |= blackfriday.EXTENSION_SPACE_HEADERS
+ extensions |= blackfriday.EXTENSION_FOOTNOTES
+ extensions |= blackfriday.EXTENSION_TITLEBLOCK
+
+ out := blackfriday.Markdown(doc, renderer, extensions)
+
+ outFile, err := os.Create(*outFilePath)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+ defer outFile.Close()
+ _, err = outFile.Write(out)
+ if err != nil {
+ fmt.Println(err)
+ os.Exit(1)
+ }
+}
diff --git a/vendor/src/github.com/russross/blackfriday/.travis.yml b/vendor/src/github.com/russross/blackfriday/.travis.yml
new file mode 100644
index 0000000..4dd7a1c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/.travis.yml
@@ -0,0 +1,17 @@
+# Travis CI (http://travis-ci.org/) is a continuous integration service for
+# open source projects. This file configures it to run unit tests for
+# blackfriday.
+
+language: go
+
+go:
+ - 1.2
+ - 1.3
+ - 1.4
+
+install:
+ - go get -d -t -v ./...
+ - go build -v ./...
+
+script:
+ - go test -v ./...
diff --git a/vendor/src/github.com/russross/blackfriday/LICENSE.txt b/vendor/src/github.com/russross/blackfriday/LICENSE.txt
new file mode 100644
index 0000000..2885af3
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/LICENSE.txt
@@ -0,0 +1,29 @@
+Blackfriday is distributed under the Simplified BSD License:
+
+> Copyright © 2011 Russ Ross
+> All rights reserved.
+>
+> Redistribution and use in source and binary forms, with or without
+> modification, are permitted provided that the following conditions
+> are met:
+>
+> 1. Redistributions of source code must retain the above copyright
+> notice, this list of conditions and the following disclaimer.
+>
+> 2. Redistributions in binary form must reproduce the above
+> copyright notice, this list of conditions and the following
+> disclaimer in the documentation and/or other materials provided with
+> the distribution.
+>
+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+> POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/src/github.com/russross/blackfriday/README.md b/vendor/src/github.com/russross/blackfriday/README.md
new file mode 100644
index 0000000..1bb985d
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/README.md
@@ -0,0 +1,246 @@
+Blackfriday [![Build Status](https://travis-ci.org/russross/blackfriday.svg?branch=master)](https://travis-ci.org/russross/blackfriday)
+===========
+
+Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It
+is paranoid about its input (so you can safely feed it user-supplied
+data), it is fast, it supports common extensions (tables, smart
+punctuation substitutions, etc.), and it is safe for all utf-8
+(unicode) input.
+
+HTML output is currently supported, along with Smartypants
+extensions. An experimental LaTeX output engine is also included.
+
+It started as a translation from C of [Sundown][3].
+
+
+Installation
+------------
+
+Blackfriday is compatible with Go 1. If you are using an older
+release of Go, consider using v1.1 of blackfriday, which was based
+on the last stable release of Go prior to Go 1. You can find it as a
+tagged commit on github.
+
+With Go 1 and git installed:
+
+ go get github.com/russross/blackfriday
+
+will download, compile, and install the package into your `$GOPATH`
+directory hierarchy. Alternatively, you can achieve the same if you
+import it into a project:
+
+ import "github.com/russross/blackfriday"
+
+and `go get` without parameters.
+
+Usage
+-----
+
+For basic usage, it is as simple as getting your input into a byte
+slice and calling:
+
+ output := blackfriday.MarkdownBasic(input)
+
+This renders it with no extensions enabled. To get a more useful
+feature set, use this instead:
+
+ output := blackfriday.MarkdownCommon(input)
+
+### Sanitize untrusted content
+
+Blackfriday itself does nothing to protect against malicious content. If you are
+dealing with user-supplied markdown, we recommend running blackfriday's output
+through HTML sanitizer such as
+[Bluemonday](https://github.com/microcosm-cc/bluemonday).
+
+Here's an example of simple usage of blackfriday together with bluemonday:
+
+``` go
+import (
+ "github.com/microcosm-cc/bluemonday"
+ "github.com/russross/blackfriday"
+)
+
+// ...
+unsafe := blackfriday.MarkdownCommon(input)
+html := bluemonday.UGCPolicy().SanitizeBytes(unsafe)
+```
+
+### Custom options
+
+If you want to customize the set of options, first get a renderer
+(currently either the HTML or LaTeX output engines), then use it to
+call the more general `Markdown` function. For examples, see the
+implementations of `MarkdownBasic` and `MarkdownCommon` in
+`markdown.go`.
+
+You can also check out `blackfriday-tool` for a more complete example
+of how to use it. Download and install it using:
+
+ go get github.com/russross/blackfriday-tool
+
+This is a simple command-line tool that allows you to process a
+markdown file using a standalone program. You can also browse the
+source directly on github if you are just looking for some example
+code:
+
+* <http://github.com/russross/blackfriday-tool>
+
+Note that if you have not already done so, installing
+`blackfriday-tool` will be sufficient to download and install
+blackfriday in addition to the tool itself. The tool binary will be
+installed in `$GOPATH/bin`. This is a statically-linked binary that
+can be copied to wherever you need it without worrying about
+dependencies and library versions.
+
+
+Features
+--------
+
+All features of Sundown are supported, including:
+
+* **Compatibility**. The Markdown v1.0.3 test suite passes with
+ the `--tidy` option. Without `--tidy`, the differences are
+ mostly in whitespace and entity escaping, where blackfriday is
+ more consistent and cleaner.
+
+* **Common extensions**, including table support, fenced code
+ blocks, autolinks, strikethroughs, non-strict emphasis, etc.
+
+* **Safety**. Blackfriday is paranoid when parsing, making it safe
+ to feed untrusted user input without fear of bad things
+ happening. The test suite stress tests this and there are no
+ known inputs that make it crash. If you find one, please let me
+ know and send me the input that does it.
+
+ NOTE: "safety" in this context means *runtime safety only*. In order to
+ protect yourself agains JavaScript injection in untrusted content, see
+ [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
+
+* **Fast processing**. It is fast enough to render on-demand in
+ most web applications without having to cache the output.
+
+* **Thread safety**. You can run multiple parsers in different
+ goroutines without ill effect. There is no dependence on global
+ shared state.
+
+* **Minimal dependencies**. Blackfriday only depends on standard
+ library packages in Go. The source code is pretty
+ self-contained, so it is easy to add to any project, including
+ Google App Engine projects.
+
+* **Standards compliant**. Output successfully validates using the
+ W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
+
+
+Extensions
+----------
+
+In addition to the standard markdown syntax, this package
+implements the following extensions:
+
+* **Intra-word emphasis supression**. The `_` character is
+ commonly used inside words when discussing code, so having
+ markdown interpret it as an emphasis command is usually the
+ wrong thing. Blackfriday lets you treat all emphasis markers as
+ normal characters when they occur inside a word.
+
+* **Tables**. Tables can be created by drawing them in the input
+ using a simple syntax:
+
+ ```
+ Name | Age
+ --------|------
+ Bob | 27
+ Alice | 23
+ ```
+
+* **Fenced code blocks**. In addition to the normal 4-space
+ indentation to mark code blocks, you can explicitly mark them
+ and supply a language (to make syntax highlighting simple). Just
+ mark it like this:
+
+ ``` go
+ func getTrue() bool {
+ return true
+ }
+ ```
+
+ You can use 3 or more backticks to mark the beginning of the
+ block, and the same number to mark the end of the block.
+
+* **Autolinking**. Blackfriday can find URLs that have not been
+ explicitly marked as links and turn them into links.
+
+* **Strikethrough**. Use two tildes (`~~`) to mark text that
+ should be crossed out.
+
+* **Hard line breaks**. With this extension enabled (it is off by
+ default in the `MarkdownBasic` and `MarkdownCommon` convenience
+ functions), newlines in the input translate into line breaks in
+ the output.
+
+* **Smart quotes**. Smartypants-style punctuation substitution is
+ supported, turning normal double- and single-quote marks into
+ curly quotes, etc.
+
+* **LaTeX-style dash parsing** is an additional option, where `--`
+ is translated into `–`, and `---` is translated into
+ `—`. This differs from most smartypants processors, which
+ turn a single hyphen into an ndash and a double hyphen into an
+ mdash.
+
+* **Smart fractions**, where anything that looks like a fraction
+ is translated into suitable HTML (instead of just a few special
+ cases like most smartypant processors). For example, `4/5`
+ becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as
+ <sup>4</sup>⁄<sub>5</sub>.
+
+
+Other renderers
+---------------
+
+Blackfriday is structured to allow alternative rendering engines. Here
+are a few of note:
+
+* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/go/github_flavored_markdown):
+ provides a GitHub Flavored Markdown renderer with fenced code block
+ highlighting, clickable header anchor links.
+
+ It's not customizable, and its goal is to produce HTML output
+ equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode),
+ except the rendering is performed locally.
+
+* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt,
+ but for markdown.
+
+* LaTeX output: renders output as LaTeX. This is currently part of the
+ main Blackfriday repository, but may be split into its own project
+ in the future. If you are interested in owning and maintaining the
+ LaTeX output component, please be in touch.
+
+ It renders some basic documents, but is only experimental at this
+ point. In particular, it does not do any inline escaping, so input
+ that happens to look like LaTeX code will be passed through without
+ modification.
+
+
+Todo
+----
+
+* More unit testing
+* Improve unicode support. It does not understand all unicode
+ rules (about what constitutes a letter, a punctuation symbol,
+ etc.), so it may fail to detect word boundaries correctly in
+ some instances. It is safe on all utf-8 input.
+
+
+License
+-------
+
+[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt)
+
+
+ [1]: http://daringfireball.net/projects/markdown/ "Markdown"
+ [2]: http://golang.org/ "Go Language"
+ [3]: https://github.com/vmg/sundown "Sundown"
diff --git a/vendor/src/github.com/russross/blackfriday/block.go b/vendor/src/github.com/russross/blackfriday/block.go
new file mode 100644
index 0000000..59c6d28
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/block.go
@@ -0,0 +1,1339 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Functions to parse block-level elements.
+//
+
+package blackfriday
+
+import (
+ "bytes"
+
+ "github.com/shurcooL/sanitized_anchor_name"
+)
+
+// Parse block-level data.
+// Note: this function and many that it calls assume that
+// the input buffer ends with a newline.
+func (p *parser) block(out *bytes.Buffer, data []byte) {
+ if len(data) == 0 || data[len(data)-1] != '\n' {
+ panic("block input is missing terminating newline")
+ }
+
+ // this is called recursively: enforce a maximum depth
+ if p.nesting >= p.maxNesting {
+ return
+ }
+ p.nesting++
+
+ // parse out one block-level construct at a time
+ for len(data) > 0 {
+ // prefixed header:
+ //
+ // # Header 1
+ // ## Header 2
+ // ...
+ // ###### Header 6
+ if p.isPrefixHeader(data) {
+ data = data[p.prefixHeader(out, data):]
+ continue
+ }
+
+ // block of preformatted HTML:
+ //
+ // <div>
+ // ...
+ // </div>
+ if data[0] == '<' {
+ if i := p.html(out, data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // title block
+ //
+ // % stuff
+ // % more stuff
+ // % even more stuff
+ if p.flags&EXTENSION_TITLEBLOCK != 0 {
+ if data[0] == '%' {
+ if i := p.titleBlock(out, data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+ }
+
+ // blank lines. note: returns the # of bytes to skip
+ if i := p.isEmpty(data); i > 0 {
+ data = data[i:]
+ continue
+ }
+
+ // indented code block:
+ //
+ // func max(a, b int) int {
+ // if a > b {
+ // return a
+ // }
+ // return b
+ // }
+ if p.codePrefix(data) > 0 {
+ data = data[p.code(out, data):]
+ continue
+ }
+
+ // fenced code block:
+ //
+ // ``` go
+ // func fact(n int) int {
+ // if n <= 1 {
+ // return n
+ // }
+ // return n * fact(n-1)
+ // }
+ // ```
+ if p.flags&EXTENSION_FENCED_CODE != 0 {
+ if i := p.fencedCode(out, data, true); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // horizontal rule:
+ //
+ // ------
+ // or
+ // ******
+ // or
+ // ______
+ if p.isHRule(data) {
+ p.r.HRule(out)
+ var i int
+ for i = 0; data[i] != '\n'; i++ {
+ }
+ data = data[i:]
+ continue
+ }
+
+ // block quote:
+ //
+ // > A big quote I found somewhere
+ // > on the web
+ if p.quotePrefix(data) > 0 {
+ data = data[p.quote(out, data):]
+ continue
+ }
+
+ // table:
+ //
+ // Name | Age | Phone
+ // ------|-----|---------
+ // Bob | 31 | 555-1234
+ // Alice | 27 | 555-4321
+ if p.flags&EXTENSION_TABLES != 0 {
+ if i := p.table(out, data); i > 0 {
+ data = data[i:]
+ continue
+ }
+ }
+
+ // an itemized/unordered list:
+ //
+ // * Item 1
+ // * Item 2
+ //
+ // also works with + or -
+ if p.uliPrefix(data) > 0 {
+ data = data[p.list(out, data, 0):]
+ continue
+ }
+
+ // a numbered/ordered list:
+ //
+ // 1. Item 1
+ // 2. Item 2
+ if p.oliPrefix(data) > 0 {
+ data = data[p.list(out, data, LIST_TYPE_ORDERED):]
+ continue
+ }
+
+ // anything else must look like a normal paragraph
+ // note: this finds underlined headers, too
+ data = data[p.paragraph(out, data):]
+ }
+
+ p.nesting--
+}
+
+func (p *parser) isPrefixHeader(data []byte) bool {
+ if data[0] != '#' {
+ return false
+ }
+
+ if p.flags&EXTENSION_SPACE_HEADERS != 0 {
+ level := 0
+ for level < 6 && data[level] == '#' {
+ level++
+ }
+ if data[level] != ' ' {
+ return false
+ }
+ }
+ return true
+}
+
+func (p *parser) prefixHeader(out *bytes.Buffer, data []byte) int {
+ level := 0
+ for level < 6 && data[level] == '#' {
+ level++
+ }
+ i, end := 0, 0
+ for i = level; data[i] == ' '; i++ {
+ }
+ for end = i; data[end] != '\n'; end++ {
+ }
+ skip := end
+ id := ""
+ if p.flags&EXTENSION_HEADER_IDS != 0 {
+ j, k := 0, 0
+ // find start/end of header id
+ for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ {
+ }
+ for k = j + 1; k < end && data[k] != '}'; k++ {
+ }
+ // extract header id iff found
+ if j < end && k < end {
+ id = string(data[j+2 : k])
+ end = j
+ skip = k + 1
+ for end > 0 && data[end-1] == ' ' {
+ end--
+ }
+ }
+ }
+ for end > 0 && data[end-1] == '#' {
+ end--
+ }
+ for end > 0 && data[end-1] == ' ' {
+ end--
+ }
+ if end > i {
+ if id == "" && p.flags&EXTENSION_AUTO_HEADER_IDS != 0 {
+ id = sanitized_anchor_name.Create(string(data[i:end]))
+ }
+ work := func() bool {
+ p.inline(out, data[i:end])
+ return true
+ }
+ p.r.Header(out, work, level, id)
+ }
+ return skip
+}
+
+func (p *parser) isUnderlinedHeader(data []byte) int {
+ // test of level 1 header
+ if data[0] == '=' {
+ i := 1
+ for data[i] == '=' {
+ i++
+ }
+ for data[i] == ' ' {
+ i++
+ }
+ if data[i] == '\n' {
+ return 1
+ } else {
+ return 0
+ }
+ }
+
+ // test of level 2 header
+ if data[0] == '-' {
+ i := 1
+ for data[i] == '-' {
+ i++
+ }
+ for data[i] == ' ' {
+ i++
+ }
+ if data[i] == '\n' {
+ return 2
+ } else {
+ return 0
+ }
+ }
+
+ return 0
+}
+
+func (p *parser) titleBlock(out *bytes.Buffer, data []byte, doRender bool) int {
+ if data[0] != '%' {
+ return 0
+ }
+ splitData := bytes.Split(data, []byte("\n"))
+ var i int
+ for idx, b := range splitData {
+ if !bytes.HasPrefix(b, []byte("%")) {
+ i = idx // - 1
+ break
+ }
+ }
+
+ data = bytes.Join(splitData[0:i], []byte("\n"))
+ p.r.TitleBlock(out, data)
+
+ return len(data)
+}
+
+func (p *parser) html(out *bytes.Buffer, data []byte, doRender bool) int {
+ var i, j int
+
+ // identify the opening tag
+ if data[0] != '<' {
+ return 0
+ }
+ curtag, tagfound := p.htmlFindTag(data[1:])
+
+ // handle special cases
+ if !tagfound {
+ // check for an HTML comment
+ if size := p.htmlComment(out, data, doRender); size > 0 {
+ return size
+ }
+
+ // check for an <hr> tag
+ if size := p.htmlHr(out, data, doRender); size > 0 {
+ return size
+ }
+
+ // no special case recognized
+ return 0
+ }
+
+ // look for an unindented matching closing tag
+ // followed by a blank line
+ found := false
+ /*
+ closetag := []byte("\n</" + curtag + ">")
+ j = len(curtag) + 1
+ for !found {
+ // scan for a closing tag at the beginning of a line
+ if skip := bytes.Index(data[j:], closetag); skip >= 0 {
+ j += skip + len(closetag)
+ } else {
+ break
+ }
+
+ // see if it is the only thing on the line
+ if skip := p.isEmpty(data[j:]); skip > 0 {
+ // see if it is followed by a blank line/eof
+ j += skip
+ if j >= len(data) {
+ found = true
+ i = j
+ } else {
+ if skip := p.isEmpty(data[j:]); skip > 0 {
+ j += skip
+ found = true
+ i = j
+ }
+ }
+ }
+ }
+ */
+
+ // if not found, try a second pass looking for indented match
+ // but not if tag is "ins" or "del" (following original Markdown.pl)
+ if !found && curtag != "ins" && curtag != "del" {
+ i = 1
+ for i < len(data) {
+ i++
+ for i < len(data) && !(data[i-1] == '<' && data[i] == '/') {
+ i++
+ }
+
+ if i+2+len(curtag) >= len(data) {
+ break
+ }
+
+ j = p.htmlFindEnd(curtag, data[i-1:])
+
+ if j > 0 {
+ i += j - 1
+ found = true
+ break
+ }
+ }
+ }
+
+ if !found {
+ return 0
+ }
+
+ // the end of the block has been found
+ if doRender {
+ // trim newlines
+ end := i
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ p.r.BlockHtml(out, data[:end])
+ }
+
+ return i
+}
+
+// HTML comment, lax form
+func (p *parser) htmlComment(out *bytes.Buffer, data []byte, doRender bool) int {
+ if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' {
+ return 0
+ }
+
+ i := 5
+
+ // scan for an end-of-comment marker, across lines if necessary
+ for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') {
+ i++
+ }
+ i++
+
+ // no end-of-comment marker
+ if i >= len(data) {
+ return 0
+ }
+
+ // needs to end with a blank line
+ if j := p.isEmpty(data[i:]); j > 0 {
+ size := i + j
+ if doRender {
+ // trim trailing newlines
+ end := size
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ p.r.BlockHtml(out, data[:end])
+ }
+ return size
+ }
+
+ return 0
+}
+
+// HR, which is the only self-closing block tag considered
+func (p *parser) htmlHr(out *bytes.Buffer, data []byte, doRender bool) int {
+ if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') {
+ return 0
+ }
+ if data[3] != ' ' && data[3] != '/' && data[3] != '>' {
+ // not an <hr> tag after all; at least not a valid one
+ return 0
+ }
+
+ i := 3
+ for data[i] != '>' && data[i] != '\n' {
+ i++
+ }
+
+ if data[i] == '>' {
+ i++
+ if j := p.isEmpty(data[i:]); j > 0 {
+ size := i + j
+ if doRender {
+ // trim newlines
+ end := size
+ for end > 0 && data[end-1] == '\n' {
+ end--
+ }
+ p.r.BlockHtml(out, data[:end])
+ }
+ return size
+ }
+ }
+
+ return 0
+}
+
+func (p *parser) htmlFindTag(data []byte) (string, bool) {
+ i := 0
+ for isalnum(data[i]) {
+ i++
+ }
+ key := string(data[:i])
+ if blockTags[key] {
+ return key, true
+ }
+ return "", false
+}
+
+func (p *parser) htmlFindEnd(tag string, data []byte) int {
+ // assume data[0] == '<' && data[1] == '/' already tested
+
+ // check if tag is a match
+ closetag := []byte("</" + tag + ">")
+ if !bytes.HasPrefix(data, closetag) {
+ return 0
+ }
+ i := len(closetag)
+
+ // check that the rest of the line is blank
+ skip := 0
+ if skip = p.isEmpty(data[i:]); skip == 0 {
+ return 0
+ }
+ i += skip
+ skip = 0
+
+ if i >= len(data) {
+ return i
+ }
+
+ if p.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
+ return i
+ }
+ if skip = p.isEmpty(data[i:]); skip == 0 {
+ // following line must be blank
+ return 0
+ }
+
+ return i + skip
+}
+
+func (p *parser) isEmpty(data []byte) int {
+ // it is okay to call isEmpty on an empty buffer
+ if len(data) == 0 {
+ return 0
+ }
+
+ var i int
+ for i = 0; i < len(data) && data[i] != '\n'; i++ {
+ if data[i] != ' ' && data[i] != '\t' {
+ return 0
+ }
+ }
+ return i + 1
+}
+
+func (p *parser) isHRule(data []byte) bool {
+ i := 0
+
+ // skip up to three spaces
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ // look at the hrule char
+ if data[i] != '*' && data[i] != '-' && data[i] != '_' {
+ return false
+ }
+ c := data[i]
+
+ // the whole line must be the char or whitespace
+ n := 0
+ for data[i] != '\n' {
+ switch {
+ case data[i] == c:
+ n++
+ case data[i] != ' ':
+ return false
+ }
+ i++
+ }
+
+ return n >= 3
+}
+
+func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, marker string) {
+ i, size := 0, 0
+ skip = 0
+
+ // skip up to three spaces
+ for i < len(data) && i < 3 && data[i] == ' ' {
+ i++
+ }
+ if i >= len(data) {
+ return
+ }
+
+ // check for the marker characters: ~ or `
+ if data[i] != '~' && data[i] != '`' {
+ return
+ }
+
+ c := data[i]
+
+ // the whole line must be the same char or whitespace
+ for i < len(data) && data[i] == c {
+ size++
+ i++
+ }
+
+ if i >= len(data) {
+ return
+ }
+
+ // the marker char must occur at least 3 times
+ if size < 3 {
+ return
+ }
+ marker = string(data[i-size : i])
+
+ // if this is the end marker, it must match the beginning marker
+ if oldmarker != "" && marker != oldmarker {
+ return
+ }
+
+ if syntax != nil {
+ syn := 0
+
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ if i >= len(data) {
+ return
+ }
+
+ syntaxStart := i
+
+ if data[i] == '{' {
+ i++
+ syntaxStart++
+
+ for i < len(data) && data[i] != '}' && data[i] != '\n' {
+ syn++
+ i++
+ }
+
+ if i >= len(data) || data[i] != '}' {
+ return
+ }
+
+ // strip all whitespace at the beginning and the end
+ // of the {} block
+ for syn > 0 && isspace(data[syntaxStart]) {
+ syntaxStart++
+ syn--
+ }
+
+ for syn > 0 && isspace(data[syntaxStart+syn-1]) {
+ syn--
+ }
+
+ i++
+ } else {
+ for i < len(data) && !isspace(data[i]) {
+ syn++
+ i++
+ }
+ }
+
+ language := string(data[syntaxStart : syntaxStart+syn])
+ *syntax = &language
+ }
+
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+ if i >= len(data) || data[i] != '\n' {
+ return
+ }
+
+ skip = i + 1
+ return
+}
+
+func (p *parser) fencedCode(out *bytes.Buffer, data []byte, doRender bool) int {
+ var lang *string
+ beg, marker := p.isFencedCode(data, &lang, "")
+ if beg == 0 || beg >= len(data) {
+ return 0
+ }
+
+ var work bytes.Buffer
+
+ for {
+ // safe to assume beg < len(data)
+
+ // check for the end of the code block
+ fenceEnd, _ := p.isFencedCode(data[beg:], nil, marker)
+ if fenceEnd != 0 {
+ beg += fenceEnd
+ break
+ }
+
+ // copy the current line
+ end := beg
+ for end < len(data) && data[end] != '\n' {
+ end++
+ }
+ end++
+
+ // did we reach the end of the buffer without a closing marker?
+ if end >= len(data) {
+ return 0
+ }
+
+ // verbatim copy to the working buffer
+ if doRender {
+ work.Write(data[beg:end])
+ }
+ beg = end
+ }
+
+ syntax := ""
+ if lang != nil {
+ syntax = *lang
+ }
+
+ if doRender {
+ p.r.BlockCode(out, work.Bytes(), syntax)
+ }
+
+ return beg
+}
+
+func (p *parser) table(out *bytes.Buffer, data []byte) int {
+ var header bytes.Buffer
+ i, columns := p.tableHeader(&header, data)
+ if i == 0 {
+ return 0
+ }
+
+ var body bytes.Buffer
+
+ for i < len(data) {
+ pipes, rowStart := 0, i
+ for ; data[i] != '\n'; i++ {
+ if data[i] == '|' {
+ pipes++
+ }
+ }
+
+ if pipes == 0 {
+ i = rowStart
+ break
+ }
+
+ // include the newline in data sent to tableRow
+ i++
+ p.tableRow(&body, data[rowStart:i], columns, false)
+ }
+
+ p.r.Table(out, header.Bytes(), body.Bytes(), columns)
+
+ return i
+}
+
+// check if the specified position is preceeded by an odd number of backslashes
+func isBackslashEscaped(data []byte, i int) bool {
+ backslashes := 0
+ for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' {
+ backslashes++
+ }
+ return backslashes&1 == 1
+}
+
+func (p *parser) tableHeader(out *bytes.Buffer, data []byte) (size int, columns []int) {
+ i := 0
+ colCount := 1
+ for i = 0; data[i] != '\n'; i++ {
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ colCount++
+ }
+ }
+
+ // doesn't look like a table header
+ if colCount == 1 {
+ return
+ }
+
+ // include the newline in the data sent to tableRow
+ header := data[:i+1]
+
+ // column count ignores pipes at beginning or end of line
+ if data[0] == '|' {
+ colCount--
+ }
+ if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) {
+ colCount--
+ }
+
+ columns = make([]int, colCount)
+
+ // move on to the header underline
+ i++
+ if i >= len(data) {
+ return
+ }
+
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ i++
+ }
+ for data[i] == ' ' {
+ i++
+ }
+
+ // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3
+ // and trailing | optional on last column
+ col := 0
+ for data[i] != '\n' {
+ dashes := 0
+
+ if data[i] == ':' {
+ i++
+ columns[col] |= TABLE_ALIGNMENT_LEFT
+ dashes++
+ }
+ for data[i] == '-' {
+ i++
+ dashes++
+ }
+ if data[i] == ':' {
+ i++
+ columns[col] |= TABLE_ALIGNMENT_RIGHT
+ dashes++
+ }
+ for data[i] == ' ' {
+ i++
+ }
+
+ // end of column test is messy
+ switch {
+ case dashes < 3:
+ // not a valid column
+ return
+
+ case data[i] == '|' && !isBackslashEscaped(data, i):
+ // marker found, now skip past trailing whitespace
+ col++
+ i++
+ for data[i] == ' ' {
+ i++
+ }
+
+ // trailing junk found after last column
+ if col >= colCount && data[i] != '\n' {
+ return
+ }
+
+ case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount:
+ // something else found where marker was required
+ return
+
+ case data[i] == '\n':
+ // marker is optional for the last column
+ col++
+
+ default:
+ // trailing junk found after last column
+ return
+ }
+ }
+ if col != colCount {
+ return
+ }
+
+ p.tableRow(out, header, columns, true)
+ size = i + 1
+ return
+}
+
+func (p *parser) tableRow(out *bytes.Buffer, data []byte, columns []int, header bool) {
+ i, col := 0, 0
+ var rowWork bytes.Buffer
+
+ if data[i] == '|' && !isBackslashEscaped(data, i) {
+ i++
+ }
+
+ for col = 0; col < len(columns) && i < len(data); col++ {
+ for data[i] == ' ' {
+ i++
+ }
+
+ cellStart := i
+
+ for (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' {
+ i++
+ }
+
+ cellEnd := i
+
+ // skip the end-of-cell marker, possibly taking us past end of buffer
+ i++
+
+ for cellEnd > cellStart && data[cellEnd-1] == ' ' {
+ cellEnd--
+ }
+
+ var cellWork bytes.Buffer
+ p.inline(&cellWork, data[cellStart:cellEnd])
+
+ if header {
+ p.r.TableHeaderCell(&rowWork, cellWork.Bytes(), columns[col])
+ } else {
+ p.r.TableCell(&rowWork, cellWork.Bytes(), columns[col])
+ }
+ }
+
+ // pad it out with empty columns to get the right number
+ for ; col < len(columns); col++ {
+ if header {
+ p.r.TableHeaderCell(&rowWork, nil, columns[col])
+ } else {
+ p.r.TableCell(&rowWork, nil, columns[col])
+ }
+ }
+
+ // silently ignore rows with too many cells
+
+ p.r.TableRow(out, rowWork.Bytes())
+}
+
+// returns blockquote prefix length
+func (p *parser) quotePrefix(data []byte) int {
+ i := 0
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+ if data[i] == '>' {
+ if data[i+1] == ' ' {
+ return i + 2
+ }
+ return i + 1
+ }
+ return 0
+}
+
+// parse a blockquote fragment
+func (p *parser) quote(out *bytes.Buffer, data []byte) int {
+ var raw bytes.Buffer
+ beg, end := 0, 0
+ for beg < len(data) {
+ end = beg
+ for data[end] != '\n' {
+ end++
+ }
+ end++
+
+ if pre := p.quotePrefix(data[beg:]); pre > 0 {
+ // skip the prefix
+ beg += pre
+ } else if p.isEmpty(data[beg:]) > 0 &&
+ (end >= len(data) ||
+ (p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0)) {
+ // blockquote ends with at least one blank line
+ // followed by something without a blockquote prefix
+ break
+ }
+
+ // this line is part of the blockquote
+ raw.Write(data[beg:end])
+ beg = end
+ }
+
+ var cooked bytes.Buffer
+ p.block(&cooked, raw.Bytes())
+ p.r.BlockQuote(out, cooked.Bytes())
+ return end
+}
+
+// returns prefix length for block code
+func (p *parser) codePrefix(data []byte) int {
+ if data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' {
+ return 4
+ }
+ return 0
+}
+
+func (p *parser) code(out *bytes.Buffer, data []byte) int {
+ var work bytes.Buffer
+
+ i := 0
+ for i < len(data) {
+ beg := i
+ for data[i] != '\n' {
+ i++
+ }
+ i++
+
+ blankline := p.isEmpty(data[beg:i]) > 0
+ if pre := p.codePrefix(data[beg:i]); pre > 0 {
+ beg += pre
+ } else if !blankline {
+ // non-empty, non-prefixed line breaks the pre
+ i = beg
+ break
+ }
+
+ // verbatim copy to the working buffeu
+ if blankline {
+ work.WriteByte('\n')
+ } else {
+ work.Write(data[beg:i])
+ }
+ }
+
+ // trim all the \n off the end of work
+ workbytes := work.Bytes()
+ eol := len(workbytes)
+ for eol > 0 && workbytes[eol-1] == '\n' {
+ eol--
+ }
+ if eol != len(workbytes) {
+ work.Truncate(eol)
+ }
+
+ work.WriteByte('\n')
+
+ p.r.BlockCode(out, work.Bytes(), "")
+
+ return i
+}
+
+// returns unordered list item prefix
+func (p *parser) uliPrefix(data []byte) int {
+ i := 0
+
+ // start with up to 3 spaces
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ // need a *, +, or - followed by a space
+ if (data[i] != '*' && data[i] != '+' && data[i] != '-') ||
+ data[i+1] != ' ' {
+ return 0
+ }
+ return i + 2
+}
+
+// returns ordered list item prefix
+func (p *parser) oliPrefix(data []byte) int {
+ i := 0
+
+ // start with up to 3 spaces
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ // count the digits
+ start := i
+ for data[i] >= '0' && data[i] <= '9' {
+ i++
+ }
+
+ // we need >= 1 digits followed by a dot and a space
+ if start == i || data[i] != '.' || data[i+1] != ' ' {
+ return 0
+ }
+ return i + 2
+}
+
+// parse ordered or unordered list block
+func (p *parser) list(out *bytes.Buffer, data []byte, flags int) int {
+ i := 0
+ flags |= LIST_ITEM_BEGINNING_OF_LIST
+ work := func() bool {
+ for i < len(data) {
+ skip := p.listItem(out, data[i:], &flags)
+ i += skip
+
+ if skip == 0 || flags&LIST_ITEM_END_OF_LIST != 0 {
+ break
+ }
+ flags &= ^LIST_ITEM_BEGINNING_OF_LIST
+ }
+ return true
+ }
+
+ p.r.List(out, work, flags)
+ return i
+}
+
+// Parse a single list item.
+// Assumes initial prefix is already removed if this is a sublist.
+func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int {
+ // keep track of the indentation of the first line
+ itemIndent := 0
+ for itemIndent < 3 && data[itemIndent] == ' ' {
+ itemIndent++
+ }
+
+ i := p.uliPrefix(data)
+ if i == 0 {
+ i = p.oliPrefix(data)
+ }
+ if i == 0 {
+ return 0
+ }
+
+ // skip leading whitespace on first line
+ for data[i] == ' ' {
+ i++
+ }
+
+ // find the end of the line
+ line := i
+ for data[i-1] != '\n' {
+ i++
+ }
+
+ // get working buffer
+ var raw bytes.Buffer
+
+ // put the first line into the working buffer
+ raw.Write(data[line:i])
+ line = i
+
+ // process the following lines
+ containsBlankLine := false
+ sublist := 0
+
+gatherlines:
+ for line < len(data) {
+ i++
+
+ // find the end of this line
+ for data[i-1] != '\n' {
+ i++
+ }
+
+ // if it is an empty line, guess that it is part of this item
+ // and move on to the next line
+ if p.isEmpty(data[line:i]) > 0 {
+ containsBlankLine = true
+ line = i
+ continue
+ }
+
+ // calculate the indentation
+ indent := 0
+ for indent < 4 && line+indent < i && data[line+indent] == ' ' {
+ indent++
+ }
+
+ chunk := data[line+indent : i]
+
+ // evaluate how this line fits in
+ switch {
+ // is this a nested list item?
+ case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) ||
+ p.oliPrefix(chunk) > 0:
+
+ if containsBlankLine {
+ *flags |= LIST_ITEM_CONTAINS_BLOCK
+ }
+
+ // to be a nested list, it must be indented more
+ // if not, it is the next item in the same list
+ if indent <= itemIndent {
+ break gatherlines
+ }
+
+ // is this the first item in the the nested list?
+ if sublist == 0 {
+ sublist = raw.Len()
+ }
+
+ // is this a nested prefix header?
+ case p.isPrefixHeader(chunk):
+ // if the header is not indented, it is not nested in the list
+ // and thus ends the list
+ if containsBlankLine && indent < 4 {
+ *flags |= LIST_ITEM_END_OF_LIST
+ break gatherlines
+ }
+ *flags |= LIST_ITEM_CONTAINS_BLOCK
+
+ // anything following an empty line is only part
+ // of this item if it is indented 4 spaces
+ // (regardless of the indentation of the beginning of the item)
+ case containsBlankLine && indent < 4:
+ *flags |= LIST_ITEM_END_OF_LIST
+ break gatherlines
+
+ // a blank line means this should be parsed as a block
+ case containsBlankLine:
+ raw.WriteByte('\n')
+ *flags |= LIST_ITEM_CONTAINS_BLOCK
+ }
+
+ // if this line was preceeded by one or more blanks,
+ // re-introduce the blank into the buffer
+ if containsBlankLine {
+ containsBlankLine = false
+ raw.WriteByte('\n')
+ }
+
+ // add the line into the working buffer without prefix
+ raw.Write(data[line+indent : i])
+
+ line = i
+ }
+
+ rawBytes := raw.Bytes()
+
+ // render the contents of the list item
+ var cooked bytes.Buffer
+ if *flags&LIST_ITEM_CONTAINS_BLOCK != 0 {
+ // intermediate render of block li
+ if sublist > 0 {
+ p.block(&cooked, rawBytes[:sublist])
+ p.block(&cooked, rawBytes[sublist:])
+ } else {
+ p.block(&cooked, rawBytes)
+ }
+ } else {
+ // intermediate render of inline li
+ if sublist > 0 {
+ p.inline(&cooked, rawBytes[:sublist])
+ p.block(&cooked, rawBytes[sublist:])
+ } else {
+ p.inline(&cooked, rawBytes)
+ }
+ }
+
+ // render the actual list item
+ cookedBytes := cooked.Bytes()
+ parsedEnd := len(cookedBytes)
+
+ // strip trailing newlines
+ for parsedEnd > 0 && cookedBytes[parsedEnd-1] == '\n' {
+ parsedEnd--
+ }
+ p.r.ListItem(out, cookedBytes[:parsedEnd], *flags)
+
+ return line
+}
+
+// render a single paragraph that has already been parsed out
+func (p *parser) renderParagraph(out *bytes.Buffer, data []byte) {
+ if len(data) == 0 {
+ return
+ }
+
+ // trim leading spaces
+ beg := 0
+ for data[beg] == ' ' {
+ beg++
+ }
+
+ // trim trailing newline
+ end := len(data) - 1
+
+ // trim trailing spaces
+ for end > beg && data[end-1] == ' ' {
+ end--
+ }
+
+ work := func() bool {
+ p.inline(out, data[beg:end])
+ return true
+ }
+ p.r.Paragraph(out, work)
+}
+
+func (p *parser) paragraph(out *bytes.Buffer, data []byte) int {
+ // prev: index of 1st char of previous line
+ // line: index of 1st char of current line
+ // i: index of cursor/end of current line
+ var prev, line, i int
+
+ // keep going until we find something to mark the end of the paragraph
+ for i < len(data) {
+ // mark the beginning of the current line
+ prev = line
+ current := data[i:]
+ line = i
+
+ // did we find a blank line marking the end of the paragraph?
+ if n := p.isEmpty(current); n > 0 {
+ p.renderParagraph(out, data[:i])
+ return i + n
+ }
+
+ // an underline under some text marks a header, so our paragraph ended on prev line
+ if i > 0 {
+ if level := p.isUnderlinedHeader(current); level > 0 {
+ // render the paragraph
+ p.renderParagraph(out, data[:prev])
+
+ // ignore leading and trailing whitespace
+ eol := i - 1
+ for prev < eol && data[prev] == ' ' {
+ prev++
+ }
+ for eol > prev && data[eol-1] == ' ' {
+ eol--
+ }
+
+ // render the header
+ // this ugly double closure avoids forcing variables onto the heap
+ work := func(o *bytes.Buffer, pp *parser, d []byte) func() bool {
+ return func() bool {
+ pp.inline(o, d)
+ return true
+ }
+ }(out, p, data[prev:eol])
+
+ id := ""
+ if p.flags&EXTENSION_AUTO_HEADER_IDS != 0 {
+ id = sanitized_anchor_name.Create(string(data[prev:eol]))
+ }
+
+ p.r.Header(out, work, level, id)
+
+ // find the end of the underline
+ for data[i] != '\n' {
+ i++
+ }
+ return i
+ }
+ }
+
+ // if the next line starts a block of HTML, then the paragraph ends here
+ if p.flags&EXTENSION_LAX_HTML_BLOCKS != 0 {
+ if data[i] == '<' && p.html(out, current, false) > 0 {
+ // rewind to before the HTML block
+ p.renderParagraph(out, data[:i])
+ return i
+ }
+ }
+
+ // if there's a prefixed header or a horizontal rule after this, paragraph is over
+ if p.isPrefixHeader(current) || p.isHRule(current) {
+ p.renderParagraph(out, data[:i])
+ return i
+ }
+
+ // if there's a list after this, paragraph is over
+ if p.flags&EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK != 0 {
+ if p.uliPrefix(current) != 0 ||
+ p.oliPrefix(current) != 0 ||
+ p.quotePrefix(current) != 0 ||
+ p.codePrefix(current) != 0 {
+ p.renderParagraph(out, data[:i])
+ return i
+ }
+ }
+
+ // otherwise, scan to the beginning of the next line
+ for data[i] != '\n' {
+ i++
+ }
+ i++
+ }
+
+ p.renderParagraph(out, data[:i])
+ return i
+}
diff --git a/vendor/src/github.com/russross/blackfriday/block_test.go b/vendor/src/github.com/russross/blackfriday/block_test.go
new file mode 100644
index 0000000..b726c07
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/block_test.go
@@ -0,0 +1,1296 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Unit tests for block parsing
+//
+
+package blackfriday
+
+import (
+ "testing"
+)
+
+func runMarkdownBlockWithRenderer(input string, extensions int, renderer Renderer) string {
+ return string(Markdown([]byte(input), renderer, extensions))
+}
+
+func runMarkdownBlock(input string, extensions int) string {
+ htmlFlags := 0
+ htmlFlags |= HTML_USE_XHTML
+
+ renderer := HtmlRenderer(htmlFlags, "", "")
+
+ return runMarkdownBlockWithRenderer(input, extensions, renderer)
+}
+
+func runnerWithRendererParameters(parameters HtmlRendererParameters) func(string, int) string {
+ return func(input string, extensions int) string {
+ htmlFlags := 0
+ htmlFlags |= HTML_USE_XHTML
+
+ renderer := HtmlRendererWithParameters(htmlFlags, "", "", parameters)
+
+ return runMarkdownBlockWithRenderer(input, extensions, renderer)
+ }
+}
+
+func doTestsBlock(t *testing.T, tests []string, extensions int) {
+ doTestsBlockWithRunner(t, tests, extensions, runMarkdownBlock)
+}
+
+func doTestsBlockWithRunner(t *testing.T, tests []string, extensions int, runner func(string, int) string) {
+ // catch and report panics
+ var candidate string
+ defer func() {
+ if err := recover(); err != nil {
+ t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
+ }
+ }()
+
+ for i := 0; i+1 < len(tests); i += 2 {
+ input := tests[i]
+ candidate = input
+ expected := tests[i+1]
+ actual := runner(candidate, extensions)
+ if actual != expected {
+ t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
+ candidate, expected, actual)
+ }
+
+ // now test every substring to stress test bounds checking
+ if !testing.Short() {
+ for start := 0; start < len(input); start++ {
+ for end := start + 1; end <= len(input); end++ {
+ candidate = input[start:end]
+ _ = runMarkdownBlock(candidate, extensions)
+ }
+ }
+ }
+ }
+}
+
+func TestPrefixHeaderNoExtensions(t *testing.T) {
+ var tests = []string{
+ "# Header 1\n",
+ "<h1>Header 1</h1>\n",
+
+ "## Header 2\n",
+ "<h2>Header 2</h2>\n",
+
+ "### Header 3\n",
+ "<h3>Header 3</h3>\n",
+
+ "#### Header 4\n",
+ "<h4>Header 4</h4>\n",
+
+ "##### Header 5\n",
+ "<h5>Header 5</h5>\n",
+
+ "###### Header 6\n",
+ "<h6>Header 6</h6>\n",
+
+ "####### Header 7\n",
+ "<h6># Header 7</h6>\n",
+
+ "#Header 1\n",
+ "<h1>Header 1</h1>\n",
+
+ "##Header 2\n",
+ "<h2>Header 2</h2>\n",
+
+ "###Header 3\n",
+ "<h3>Header 3</h3>\n",
+
+ "####Header 4\n",
+ "<h4>Header 4</h4>\n",
+
+ "#####Header 5\n",
+ "<h5>Header 5</h5>\n",
+
+ "######Header 6\n",
+ "<h6>Header 6</h6>\n",
+
+ "#######Header 7\n",
+ "<h6>#Header 7</h6>\n",
+
+ "Hello\n# Header 1\nGoodbye\n",
+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
+
+ "* List\n# Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestPrefixHeaderSpaceExtension(t *testing.T) {
+ var tests = []string{
+ "# Header 1\n",
+ "<h1>Header 1</h1>\n",
+
+ "## Header 2\n",
+ "<h2>Header 2</h2>\n",
+
+ "### Header 3\n",
+ "<h3>Header 3</h3>\n",
+
+ "#### Header 4\n",
+ "<h4>Header 4</h4>\n",
+
+ "##### Header 5\n",
+ "<h5>Header 5</h5>\n",
+
+ "###### Header 6\n",
+ "<h6>Header 6</h6>\n",
+
+ "####### Header 7\n",
+ "<p>####### Header 7</p>\n",
+
+ "#Header 1\n",
+ "<p>#Header 1</p>\n",
+
+ "##Header 2\n",
+ "<p>##Header 2</p>\n",
+
+ "###Header 3\n",
+ "<p>###Header 3</p>\n",
+
+ "####Header 4\n",
+ "<p>####Header 4</p>\n",
+
+ "#####Header 5\n",
+ "<p>#####Header 5</p>\n",
+
+ "######Header 6\n",
+ "<p>######Header 6</p>\n",
+
+ "#######Header 7\n",
+ "<p>#######Header 7</p>\n",
+
+ "Hello\n# Header 1\nGoodbye\n",
+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
+
+ "* List\n# Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header\n* List\n",
+ "<ul>\n<li>List\n#Header</li>\n<li>List</li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS)
+}
+
+func TestPrefixHeaderIdExtension(t *testing.T) {
+ var tests = []string{
+ "# Header 1 {#someid}\n",
+ "<h1 id=\"someid\">Header 1</h1>\n",
+
+ "# Header 1 {#someid} \n",
+ "<h1 id=\"someid\">Header 1</h1>\n",
+
+ "# Header 1 {#someid}\n",
+ "<h1 id=\"someid\">Header 1</h1>\n",
+
+ "# Header 1 {#someid\n",
+ "<h1>Header 1 {#someid</h1>\n",
+
+ "# Header 1 {#someid\n",
+ "<h1>Header 1 {#someid</h1>\n",
+
+ "# Header 1 {#someid}}\n",
+ "<h1 id=\"someid\">Header 1</h1>\n\n<p>}</p>\n",
+
+ "## Header 2 {#someid}\n",
+ "<h2 id=\"someid\">Header 2</h2>\n",
+
+ "### Header 3 {#someid}\n",
+ "<h3 id=\"someid\">Header 3</h3>\n",
+
+ "#### Header 4 {#someid}\n",
+ "<h4 id=\"someid\">Header 4</h4>\n",
+
+ "##### Header 5 {#someid}\n",
+ "<h5 id=\"someid\">Header 5</h5>\n",
+
+ "###### Header 6 {#someid}\n",
+ "<h6 id=\"someid\">Header 6</h6>\n",
+
+ "####### Header 7 {#someid}\n",
+ "<h6 id=\"someid\"># Header 7</h6>\n",
+
+ "# Header 1 # {#someid}\n",
+ "<h1 id=\"someid\">Header 1</h1>\n",
+
+ "## Header 2 ## {#someid}\n",
+ "<h2 id=\"someid\">Header 2</h2>\n",
+
+ "Hello\n# Header 1\nGoodbye\n",
+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
+
+ "* List\n# Header {#someid}\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header {#someid}\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header {#someid}\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1 id=\"someid\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_HEADER_IDS)
+}
+
+func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
+ var tests = []string{
+ "# header 1 {#someid}\n",
+ "<h1 id=\"PRE:someid:POST\">header 1</h1>\n",
+
+ "## header 2 {#someid}\n",
+ "<h2 id=\"PRE:someid:POST\">header 2</h2>\n",
+
+ "### header 3 {#someid}\n",
+ "<h3 id=\"PRE:someid:POST\">header 3</h3>\n",
+
+ "#### header 4 {#someid}\n",
+ "<h4 id=\"PRE:someid:POST\">header 4</h4>\n",
+
+ "##### header 5 {#someid}\n",
+ "<h5 id=\"PRE:someid:POST\">header 5</h5>\n",
+
+ "###### header 6 {#someid}\n",
+ "<h6 id=\"PRE:someid:POST\">header 6</h6>\n",
+
+ "####### header 7 {#someid}\n",
+ "<h6 id=\"PRE:someid:POST\"># header 7</h6>\n",
+
+ "# header 1 # {#someid}\n",
+ "<h1 id=\"PRE:someid:POST\">header 1</h1>\n",
+
+ "## header 2 ## {#someid}\n",
+ "<h2 id=\"PRE:someid:POST\">header 2</h2>\n",
+
+ "* List\n# Header {#someid}\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:someid:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header {#someid}\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:someid:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header {#someid}\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1 id=\"PRE:someid:POST\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
+ }
+
+ parameters := HtmlRendererParameters{
+ HeaderIDPrefix: "PRE:",
+ HeaderIDSuffix: ":POST",
+ }
+
+ doTestsBlockWithRunner(t, tests, EXTENSION_HEADER_IDS, runnerWithRendererParameters(parameters))
+}
+
+func TestPrefixAutoHeaderIdExtension(t *testing.T) {
+ var tests = []string{
+ "# Header 1\n",
+ "<h1 id=\"header-1\">Header 1</h1>\n",
+
+ "# Header 1 \n",
+ "<h1 id=\"header-1\">Header 1</h1>\n",
+
+ "## Header 2\n",
+ "<h2 id=\"header-2\">Header 2</h2>\n",
+
+ "### Header 3\n",
+ "<h3 id=\"header-3\">Header 3</h3>\n",
+
+ "#### Header 4\n",
+ "<h4 id=\"header-4\">Header 4</h4>\n",
+
+ "##### Header 5\n",
+ "<h5 id=\"header-5\">Header 5</h5>\n",
+
+ "###### Header 6\n",
+ "<h6 id=\"header-6\">Header 6</h6>\n",
+
+ "####### Header 7\n",
+ "<h6 id=\"header-7\"># Header 7</h6>\n",
+
+ "Hello\n# Header 1\nGoodbye\n",
+ "<p>Hello</p>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<p>Goodbye</p>\n",
+
+ "* List\n# Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"header\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"header\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1 id=\"nested-header\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
+
+ "# Header\n\n# Header\n",
+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n",
+
+ "# Header 1\n\n# Header 1",
+ "<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n",
+
+ "# Header\n\n# Header 1\n\n# Header\n\n# Header",
+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header</h1>\n\n<h1 id=\"header-1-2\">Header</h1>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS)
+}
+
+func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
+ var tests = []string{
+ "# Header 1\n",
+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n",
+
+ "# Header 1 \n",
+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n",
+
+ "## Header 2\n",
+ "<h2 id=\"PRE:header-2:POST\">Header 2</h2>\n",
+
+ "### Header 3\n",
+ "<h3 id=\"PRE:header-3:POST\">Header 3</h3>\n",
+
+ "#### Header 4\n",
+ "<h4 id=\"PRE:header-4:POST\">Header 4</h4>\n",
+
+ "##### Header 5\n",
+ "<h5 id=\"PRE:header-5:POST\">Header 5</h5>\n",
+
+ "###### Header 6\n",
+ "<h6 id=\"PRE:header-6:POST\">Header 6</h6>\n",
+
+ "####### Header 7\n",
+ "<h6 id=\"PRE:header-7:POST\"># Header 7</h6>\n",
+
+ "Hello\n# Header 1\nGoodbye\n",
+ "<p>Hello</p>\n\n<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<p>Goodbye</p>\n",
+
+ "* List\n# Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:header:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n#Header\n* List\n",
+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:header:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n",
+
+ "* List\n * Nested list\n # Nested header\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
+ "<h1 id=\"PRE:nested-header:POST\">Nested header</h1></li>\n</ul></li>\n</ul>\n",
+
+ "# Header\n\n# Header\n",
+ "<h1 id=\"PRE:header:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1:POST\">Header</h1>\n",
+
+ "# Header 1\n\n# Header 1",
+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<h1 id=\"PRE:header-1-1:POST\">Header 1</h1>\n",
+
+ "# Header\n\n# Header 1\n\n# Header\n\n# Header",
+ "<h1 id=\"PRE:header:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<h1 id=\"PRE:header-1-1:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1-2:POST\">Header</h1>\n",
+ }
+
+ parameters := HtmlRendererParameters{
+ HeaderIDPrefix: "PRE:",
+ HeaderIDSuffix: ":POST",
+ }
+
+ doTestsBlockWithRunner(t, tests, EXTENSION_AUTO_HEADER_IDS, runnerWithRendererParameters(parameters))
+}
+
+func TestPrefixMultipleHeaderExtensions(t *testing.T) {
+ var tests = []string{
+ "# Header\n\n# Header {#header}\n\n# Header 1",
+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS|EXTENSION_HEADER_IDS)
+}
+
+func TestUnderlineHeaders(t *testing.T) {
+ var tests = []string{
+ "Header 1\n========\n",
+ "<h1>Header 1</h1>\n",
+
+ "Header 2\n--------\n",
+ "<h2>Header 2</h2>\n",
+
+ "A\n=\n",
+ "<h1>A</h1>\n",
+
+ "B\n-\n",
+ "<h2>B</h2>\n",
+
+ "Paragraph\nHeader\n=\n",
+ "<p>Paragraph</p>\n\n<h1>Header</h1>\n",
+
+ "Header\n===\nParagraph\n",
+ "<h1>Header</h1>\n\n<p>Paragraph</p>\n",
+
+ "Header\n===\nAnother header\n---\n",
+ "<h1>Header</h1>\n\n<h2>Another header</h2>\n",
+
+ " Header\n======\n",
+ "<h1>Header</h1>\n",
+
+ " Code\n========\n",
+ "<pre><code>Code\n</code></pre>\n\n<p>========</p>\n",
+
+ "Header with *inline*\n=====\n",
+ "<h1>Header with <em>inline</em></h1>\n",
+
+ "* List\n * Sublist\n Not a header\n ------\n",
+ "<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n",
+
+ "Paragraph\n\n\n\n\nHeader\n===\n",
+ "<p>Paragraph</p>\n\n<h1>Header</h1>\n",
+
+ "Trailing space \n==== \n\n",
+ "<h1>Trailing space</h1>\n",
+
+ "Trailing spaces\n==== \n\n",
+ "<h1>Trailing spaces</h1>\n",
+
+ "Double underline\n=====\n=====\n",
+ "<h1>Double underline</h1>\n\n<p>=====</p>\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestUnderlineHeadersAutoIDs(t *testing.T) {
+ var tests = []string{
+ "Header 1\n========\n",
+ "<h1 id=\"header-1\">Header 1</h1>\n",
+
+ "Header 2\n--------\n",
+ "<h2 id=\"header-2\">Header 2</h2>\n",
+
+ "A\n=\n",
+ "<h1 id=\"a\">A</h1>\n",
+
+ "B\n-\n",
+ "<h2 id=\"b\">B</h2>\n",
+
+ "Paragraph\nHeader\n=\n",
+ "<p>Paragraph</p>\n\n<h1 id=\"header\">Header</h1>\n",
+
+ "Header\n===\nParagraph\n",
+ "<h1 id=\"header\">Header</h1>\n\n<p>Paragraph</p>\n",
+
+ "Header\n===\nAnother header\n---\n",
+ "<h1 id=\"header\">Header</h1>\n\n<h2 id=\"another-header\">Another header</h2>\n",
+
+ " Header\n======\n",
+ "<h1 id=\"header\">Header</h1>\n",
+
+ "Header with *inline*\n=====\n",
+ "<h1 id=\"header-with-inline\">Header with <em>inline</em></h1>\n",
+
+ "Paragraph\n\n\n\n\nHeader\n===\n",
+ "<p>Paragraph</p>\n\n<h1 id=\"header\">Header</h1>\n",
+
+ "Trailing space \n==== \n\n",
+ "<h1 id=\"trailing-space\">Trailing space</h1>\n",
+
+ "Trailing spaces\n==== \n\n",
+ "<h1 id=\"trailing-spaces\">Trailing spaces</h1>\n",
+
+ "Double underline\n=====\n=====\n",
+ "<h1 id=\"double-underline\">Double underline</h1>\n\n<p>=====</p>\n",
+
+ "Header\n======\n\nHeader\n======\n",
+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n",
+
+ "Header 1\n========\n\nHeader 1\n========\n",
+ "<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS)
+}
+
+func TestHorizontalRule(t *testing.T) {
+ var tests = []string{
+ "-\n",
+ "<p>-</p>\n",
+
+ "--\n",
+ "<p>--</p>\n",
+
+ "---\n",
+ "<hr />\n",
+
+ "----\n",
+ "<hr />\n",
+
+ "*\n",
+ "<p>*</p>\n",
+
+ "**\n",
+ "<p>**</p>\n",
+
+ "***\n",
+ "<hr />\n",
+
+ "****\n",
+ "<hr />\n",
+
+ "_\n",
+ "<p>_</p>\n",
+
+ "__\n",
+ "<p>__</p>\n",
+
+ "___\n",
+ "<hr />\n",
+
+ "____\n",
+ "<hr />\n",
+
+ "-*-\n",
+ "<p>-*-</p>\n",
+
+ "- - -\n",
+ "<hr />\n",
+
+ "* * *\n",
+ "<hr />\n",
+
+ "_ _ _\n",
+ "<hr />\n",
+
+ "-----*\n",
+ "<p>-----*</p>\n",
+
+ " ------ \n",
+ "<hr />\n",
+
+ "Hello\n***\n",
+ "<p>Hello</p>\n\n<hr />\n",
+
+ "---\n***\n___\n",
+ "<hr />\n\n<hr />\n\n<hr />\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestUnorderedList(t *testing.T) {
+ var tests = []string{
+ "* Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "* Yin\n* Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "* Ting\n* Bong\n* Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "* Yin\n\n* Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "* Ting\n\n* Bong\n* Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "+ Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "+ Yin\n+ Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "+ Ting\n+ Bong\n+ Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "+ Yin\n\n+ Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "+ Ting\n\n+ Bong\n+ Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "- Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "- Yin\n- Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "- Ting\n- Bong\n- Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "- Yin\n\n- Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "- Ting\n\n- Bong\n- Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "*Hello\n",
+ "<p>*Hello</p>\n",
+
+ "* Hello \n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "* Hello \n Next line \n",
+ "<ul>\n<li>Hello\nNext line</li>\n</ul>\n",
+
+ "Paragraph\n* No linebreak\n",
+ "<p>Paragraph\n* No linebreak</p>\n",
+
+ "Paragraph\n\n* Linebreak\n",
+ "<p>Paragraph</p>\n\n<ul>\n<li>Linebreak</li>\n</ul>\n",
+
+ "* List\n * Nested list\n",
+ "<ul>\n<li>List\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n\n * Nested list\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n Second line\n\n + Nested\n",
+ "<ul>\n<li><p>List\nSecond line</p>\n\n<ul>\n<li>Nested</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n + Nested\n\n Continued\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested</li>\n</ul>\n\n<p>Continued</p></li>\n</ul>\n",
+
+ "* List\n * shallow indent\n",
+ "<ul>\n<li>List\n\n<ul>\n<li>shallow indent</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n" +
+ " * shallow indent\n" +
+ " * part of second list\n" +
+ " * still second\n" +
+ " * almost there\n" +
+ " * third level\n",
+ "<ul>\n" +
+ "<li>List\n\n" +
+ "<ul>\n" +
+ "<li>shallow indent</li>\n" +
+ "<li>part of second list</li>\n" +
+ "<li>still second</li>\n" +
+ "<li>almost there\n\n" +
+ "<ul>\n" +
+ "<li>third level</li>\n" +
+ "</ul></li>\n" +
+ "</ul></li>\n" +
+ "</ul>\n",
+
+ "* List\n extra indent, same paragraph\n",
+ "<ul>\n<li>List\n extra indent, same paragraph</li>\n</ul>\n",
+
+ "* List\n\n code block\n",
+ "<ul>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ul>\n",
+
+ "* List\n\n code block with spaces\n",
+ "<ul>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ul>\n",
+
+ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>sublist</li>\n</ul>\n\n<p>normal text</p>\n\n<ul>\n<li>another sublist</li>\n</ul></li>\n</ul>\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestOrderedList(t *testing.T) {
+ var tests = []string{
+ "1. Hello\n",
+ "<ol>\n<li>Hello</li>\n</ol>\n",
+
+ "1. Yin\n2. Yang\n",
+ "<ol>\n<li>Yin</li>\n<li>Yang</li>\n</ol>\n",
+
+ "1. Ting\n2. Bong\n3. Goo\n",
+ "<ol>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ol>\n",
+
+ "1. Yin\n\n2. Yang\n",
+ "<ol>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ol>\n",
+
+ "1. Ting\n\n2. Bong\n3. Goo\n",
+ "<ol>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ol>\n",
+
+ "1 Hello\n",
+ "<p>1 Hello</p>\n",
+
+ "1.Hello\n",
+ "<p>1.Hello</p>\n",
+
+ "1. Hello \n",
+ "<ol>\n<li>Hello</li>\n</ol>\n",
+
+ "1. Hello \n Next line \n",
+ "<ol>\n<li>Hello\nNext line</li>\n</ol>\n",
+
+ "Paragraph\n1. No linebreak\n",
+ "<p>Paragraph\n1. No linebreak</p>\n",
+
+ "Paragraph\n\n1. Linebreak\n",
+ "<p>Paragraph</p>\n\n<ol>\n<li>Linebreak</li>\n</ol>\n",
+
+ "1. List\n 1. Nested list\n",
+ "<ol>\n<li>List\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n\n 1. Nested list\n",
+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n Second line\n\n 1. Nested\n",
+ "<ol>\n<li><p>List\nSecond line</p>\n\n<ol>\n<li>Nested</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n 1. Nested\n\n Continued\n",
+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested</li>\n</ol>\n\n<p>Continued</p></li>\n</ol>\n",
+
+ "1. List\n 1. shallow indent\n",
+ "<ol>\n<li>List\n\n<ol>\n<li>shallow indent</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n" +
+ " 1. shallow indent\n" +
+ " 2. part of second list\n" +
+ " 3. still second\n" +
+ " 4. almost there\n" +
+ " 1. third level\n",
+ "<ol>\n" +
+ "<li>List\n\n" +
+ "<ol>\n" +
+ "<li>shallow indent</li>\n" +
+ "<li>part of second list</li>\n" +
+ "<li>still second</li>\n" +
+ "<li>almost there\n\n" +
+ "<ol>\n" +
+ "<li>third level</li>\n" +
+ "</ol></li>\n" +
+ "</ol></li>\n" +
+ "</ol>\n",
+
+ "1. List\n extra indent, same paragraph\n",
+ "<ol>\n<li>List\n extra indent, same paragraph</li>\n</ol>\n",
+
+ "1. List\n\n code block\n",
+ "<ol>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ol>\n",
+
+ "1. List\n\n code block with spaces\n",
+ "<ol>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ol>\n",
+
+ "1. List\n * Mixted list\n",
+ "<ol>\n<li>List\n\n<ul>\n<li>Mixted list</li>\n</ul></li>\n</ol>\n",
+
+ "1. List\n * Mixed list\n",
+ "<ol>\n<li>List\n\n<ul>\n<li>Mixed list</li>\n</ul></li>\n</ol>\n",
+
+ "* Start with unordered\n 1. Ordered\n",
+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
+
+ "* Start with unordered\n 1. Ordered\n",
+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
+
+ "1. numbers\n1. are ignored\n",
+ "<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestPreformattedHtml(t *testing.T) {
+ var tests = []string{
+ "<div></div>\n",
+ "<div></div>\n",
+
+ "<div>\n</div>\n",
+ "<div>\n</div>\n",
+
+ "<div>\n</div>\nParagraph\n",
+ "<p><div>\n</div>\nParagraph</p>\n",
+
+ "<div class=\"foo\">\n</div>\n",
+ "<div class=\"foo\">\n</div>\n",
+
+ "<div>\nAnything here\n</div>\n",
+ "<div>\nAnything here\n</div>\n",
+
+ "<div>\n Anything here\n</div>\n",
+ "<div>\n Anything here\n</div>\n",
+
+ "<div>\nAnything here\n </div>\n",
+ "<div>\nAnything here\n </div>\n",
+
+ "<div>\nThis is *not* &proceessed\n</div>\n",
+ "<div>\nThis is *not* &proceessed\n</div>\n",
+
+ "<faketag>\n Something\n</faketag>\n",
+ "<p><faketag>\n Something\n</faketag></p>\n",
+
+ "<div>\n Something here\n</divv>\n",
+ "<p><div>\n Something here\n</divv></p>\n",
+
+ "Paragraph\n<div>\nHere? >&<\n</div>\n",
+ "<p>Paragraph\n<div>\nHere? >&<\n</div></p>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n",
+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n",
+
+ "Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n",
+ "<p>Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?</p>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<p><div>\nHow about here? >&<\n</div>\nAnd here?</p>\n",
+
+ "Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n",
+ "<p>Paragraph\n<div>\nHere? >&<\n</div></p>\n\n<p>And here?</p>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
+ }
+ doTestsBlock(t, tests, 0)
+}
+
+func TestPreformattedHtmlLax(t *testing.T) {
+ var tests = []string{
+ "Paragraph\n<div>\nHere? >&<\n</div>\n",
+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n",
+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n",
+
+ "Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
+
+ "Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n",
+
+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n",
+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_LAX_HTML_BLOCKS)
+}
+
+func TestFencedCodeBlock(t *testing.T) {
+ var tests = []string{
+ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n",
+ "<pre><code class=\"language-go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n",
+
+ "``` c\n/* special & char < > \" escaping */\n```\n",
+ "<pre><code class=\"language-c\">/* special & char < > " escaping */\n</code></pre>\n",
+
+ "``` c\nno *inline* processing ~~of text~~\n```\n",
+ "<pre><code class=\"language-c\">no *inline* processing ~~of text~~\n</code></pre>\n",
+
+ "```\nNo language\n```\n",
+ "<pre><code>No language\n</code></pre>\n",
+
+ "``` {ocaml}\nlanguage in braces\n```\n",
+ "<pre><code class=\"language-ocaml\">language in braces\n</code></pre>\n",
+
+ "``` {ocaml} \nwith extra whitespace\n```\n",
+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n",
+
+ "```{ ocaml }\nwith extra whitespace\n```\n",
+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n",
+
+ "~ ~~ java\nWith whitespace\n~~~\n",
+ "<p>~ ~~ java\nWith whitespace\n~~~</p>\n",
+
+ "~~\nonly two\n~~\n",
+ "<p>~~\nonly two\n~~</p>\n",
+
+ "```` python\nextra\n````\n",
+ "<pre><code class=\"language-python\">extra\n</code></pre>\n",
+
+ "~~~ perl\nthree to start, four to end\n~~~~\n",
+ "<p>~~~ perl\nthree to start, four to end\n~~~~</p>\n",
+
+ "~~~~ perl\nfour to start, three to end\n~~~\n",
+ "<p>~~~~ perl\nfour to start, three to end\n~~~</p>\n",
+
+ "~~~ bash\ntildes\n~~~\n",
+ "<pre><code class=\"language-bash\">tildes\n</code></pre>\n",
+
+ "``` lisp\nno ending\n",
+ "<p>``` lisp\nno ending</p>\n",
+
+ "~~~ lisp\nend with language\n~~~ lisp\n",
+ "<p>~~~ lisp\nend with language\n~~~ lisp</p>\n",
+
+ "```\nmismatched begin and end\n~~~\n",
+ "<p>```\nmismatched begin and end\n~~~</p>\n",
+
+ "~~~\nmismatched begin and end\n```\n",
+ "<p>~~~\nmismatched begin and end\n```</p>\n",
+
+ " ``` oz\nleading spaces\n```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ "``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code>``` oz\n</code></pre>\n\n<p>leading spaces\n ```</p>\n",
+
+ "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n",
+ "<p>Bla bla</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Bla Bla</p>\n",
+
+ "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nAnd some text after a fenced code block",
+ "<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n",
+
+ "`",
+ "<p>`</p>\n",
+
+ "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n\n``` oz\nmultiple code blocks work okay\n```\n\nBla Bla\n",
+ "<p>Bla bla</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Bla Bla</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>Bla Bla</p>\n",
+
+ "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nSome text in between\n``` oz\nmultiple code blocks work okay\n```\nAnd some text after a fenced code block",
+ "<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Some text in between</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_FENCED_CODE)
+}
+
+func TestTable(t *testing.T) {
+ var tests = []string{
+ "a | b\n---|---\nc | d\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td>c</td>\n<td>d</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a | b\n---|--\nc | d\n",
+ "<p>a | b\n---|--\nc | d</p>\n",
+
+ "|a|b|c|d|\n|----|----|----|---|\n|e|f|g|h|\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n<th>d</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td>e</td>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "*a*|__b__|[c](C)|d\n---|---|---|---\ne|f|g|h\n",
+ "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th><strong>b</strong></th>\n<th><a href=\"C\">c</a></th>\n<th>d</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td>e</td>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a|b|c\n---|---|---\nd|e|f\ng|h\ni|j|k|l|m\nn|o|p\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td>d</td>\n<td>e</td>\n<td>f</td>\n</tr>\n\n" +
+ "<tr>\n<td>g</td>\n<td>h</td>\n<td></td>\n</tr>\n\n" +
+ "<tr>\n<td>i</td>\n<td>j</td>\n<td>k</td>\n</tr>\n\n" +
+ "<tr>\n<td>n</td>\n<td>o</td>\n<td>p</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a|b|c\n---|---|---\n*d*|__e__|f\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td><em>d</em></td>\n<td><strong>e</strong></td>\n<td>f</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a|b|c|d\n:--|--:|:-:|---\ne|f|g|h\n",
+ "<table>\n<thead>\n<tr>\n<th align=\"left\">a</th>\n<th align=\"right\">b</th>\n" +
+ "<th align=\"center\">c</th>\n<th>d</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td align=\"left\">e</td>\n<td align=\"right\">f</td>\n" +
+ "<td align=\"center\">g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a|b|c\n---|---|---\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n<tbody>\n</tbody>\n</table>\n",
+
+ "a| b|c | d | e\n---|---|---|---|---\nf| g|h | i |j\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n<th>d</th>\n<th>e</th>\n</tr>\n</thead>\n\n" +
+ "<tbody>\n<tr>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n<td>i</td>\n<td>j</td>\n</tr>\n</tbody>\n</table>\n",
+
+ "a|b\\|c|d\n---|---|---\nf|g\\|h|i\n",
+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b|c</th>\n<th>d</th>\n</tr>\n</thead>\n\n<tbody>\n<tr>\n<td>f</td>\n<td>g|h</td>\n<td>i</td>\n</tr>\n</tbody>\n</table>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_TABLES)
+}
+
+func TestUnorderedListWith_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
+ var tests = []string{
+ "* Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "* Yin\n* Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "* Ting\n* Bong\n* Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "* Yin\n\n* Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "* Ting\n\n* Bong\n* Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "+ Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "+ Yin\n+ Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "+ Ting\n+ Bong\n+ Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "+ Yin\n\n+ Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "+ Ting\n\n+ Bong\n+ Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "- Hello\n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "- Yin\n- Yang\n",
+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n",
+
+ "- Ting\n- Bong\n- Goo\n",
+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n",
+
+ "- Yin\n\n- Yang\n",
+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n",
+
+ "- Ting\n\n- Bong\n- Goo\n",
+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n",
+
+ "*Hello\n",
+ "<p>*Hello</p>\n",
+
+ "* Hello \n",
+ "<ul>\n<li>Hello</li>\n</ul>\n",
+
+ "* Hello \n Next line \n",
+ "<ul>\n<li>Hello\nNext line</li>\n</ul>\n",
+
+ "Paragraph\n* No linebreak\n",
+ "<p>Paragraph</p>\n\n<ul>\n<li>No linebreak</li>\n</ul>\n",
+
+ "Paragraph\n\n* Linebreak\n",
+ "<p>Paragraph</p>\n\n<ul>\n<li>Linebreak</li>\n</ul>\n",
+
+ "* List\n * Nested list\n",
+ "<ul>\n<li>List\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n\n * Nested list\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n Second line\n\n + Nested\n",
+ "<ul>\n<li><p>List\nSecond line</p>\n\n<ul>\n<li>Nested</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n + Nested\n\n Continued\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested</li>\n</ul>\n\n<p>Continued</p></li>\n</ul>\n",
+
+ "* List\n * shallow indent\n",
+ "<ul>\n<li>List\n\n<ul>\n<li>shallow indent</li>\n</ul></li>\n</ul>\n",
+
+ "* List\n" +
+ " * shallow indent\n" +
+ " * part of second list\n" +
+ " * still second\n" +
+ " * almost there\n" +
+ " * third level\n",
+ "<ul>\n" +
+ "<li>List\n\n" +
+ "<ul>\n" +
+ "<li>shallow indent</li>\n" +
+ "<li>part of second list</li>\n" +
+ "<li>still second</li>\n" +
+ "<li>almost there\n\n" +
+ "<ul>\n" +
+ "<li>third level</li>\n" +
+ "</ul></li>\n" +
+ "</ul></li>\n" +
+ "</ul>\n",
+
+ "* List\n extra indent, same paragraph\n",
+ "<ul>\n<li>List\n extra indent, same paragraph</li>\n</ul>\n",
+
+ "* List\n\n code block\n",
+ "<ul>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ul>\n",
+
+ "* List\n\n code block with spaces\n",
+ "<ul>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ul>\n",
+
+ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n",
+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>sublist</li>\n</ul>\n\n<p>normal text</p>\n\n<ul>\n<li>another sublist</li>\n</ul></li>\n</ul>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
+}
+
+func TestOrderedList_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
+ var tests = []string{
+ "1. Hello\n",
+ "<ol>\n<li>Hello</li>\n</ol>\n",
+
+ "1. Yin\n2. Yang\n",
+ "<ol>\n<li>Yin</li>\n<li>Yang</li>\n</ol>\n",
+
+ "1. Ting\n2. Bong\n3. Goo\n",
+ "<ol>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ol>\n",
+
+ "1. Yin\n\n2. Yang\n",
+ "<ol>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ol>\n",
+
+ "1. Ting\n\n2. Bong\n3. Goo\n",
+ "<ol>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ol>\n",
+
+ "1 Hello\n",
+ "<p>1 Hello</p>\n",
+
+ "1.Hello\n",
+ "<p>1.Hello</p>\n",
+
+ "1. Hello \n",
+ "<ol>\n<li>Hello</li>\n</ol>\n",
+
+ "1. Hello \n Next line \n",
+ "<ol>\n<li>Hello\nNext line</li>\n</ol>\n",
+
+ "Paragraph\n1. No linebreak\n",
+ "<p>Paragraph</p>\n\n<ol>\n<li>No linebreak</li>\n</ol>\n",
+
+ "Paragraph\n\n1. Linebreak\n",
+ "<p>Paragraph</p>\n\n<ol>\n<li>Linebreak</li>\n</ol>\n",
+
+ "1. List\n 1. Nested list\n",
+ "<ol>\n<li>List\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n\n 1. Nested list\n",
+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n Second line\n\n 1. Nested\n",
+ "<ol>\n<li><p>List\nSecond line</p>\n\n<ol>\n<li>Nested</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n 1. Nested\n\n Continued\n",
+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested</li>\n</ol>\n\n<p>Continued</p></li>\n</ol>\n",
+
+ "1. List\n 1. shallow indent\n",
+ "<ol>\n<li>List\n\n<ol>\n<li>shallow indent</li>\n</ol></li>\n</ol>\n",
+
+ "1. List\n" +
+ " 1. shallow indent\n" +
+ " 2. part of second list\n" +
+ " 3. still second\n" +
+ " 4. almost there\n" +
+ " 1. third level\n",
+ "<ol>\n" +
+ "<li>List\n\n" +
+ "<ol>\n" +
+ "<li>shallow indent</li>\n" +
+ "<li>part of second list</li>\n" +
+ "<li>still second</li>\n" +
+ "<li>almost there\n\n" +
+ "<ol>\n" +
+ "<li>third level</li>\n" +
+ "</ol></li>\n" +
+ "</ol></li>\n" +
+ "</ol>\n",
+
+ "1. List\n extra indent, same paragraph\n",
+ "<ol>\n<li>List\n extra indent, same paragraph</li>\n</ol>\n",
+
+ "1. List\n\n code block\n",
+ "<ol>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ol>\n",
+
+ "1. List\n\n code block with spaces\n",
+ "<ol>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ol>\n",
+
+ "1. List\n * Mixted list\n",
+ "<ol>\n<li>List\n\n<ul>\n<li>Mixted list</li>\n</ul></li>\n</ol>\n",
+
+ "1. List\n * Mixed list\n",
+ "<ol>\n<li>List\n\n<ul>\n<li>Mixed list</li>\n</ul></li>\n</ol>\n",
+
+ "* Start with unordered\n 1. Ordered\n",
+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
+
+ "* Start with unordered\n 1. Ordered\n",
+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n",
+
+ "1. numbers\n1. are ignored\n",
+ "<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
+}
+
+func TestFencedCodeBlock_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
+ var tests = []string{
+ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n",
+ "<pre><code class=\"language-go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n",
+
+ "``` c\n/* special & char < > \" escaping */\n```\n",
+ "<pre><code class=\"language-c\">/* special & char < > " escaping */\n</code></pre>\n",
+
+ "``` c\nno *inline* processing ~~of text~~\n```\n",
+ "<pre><code class=\"language-c\">no *inline* processing ~~of text~~\n</code></pre>\n",
+
+ "```\nNo language\n```\n",
+ "<pre><code>No language\n</code></pre>\n",
+
+ "``` {ocaml}\nlanguage in braces\n```\n",
+ "<pre><code class=\"language-ocaml\">language in braces\n</code></pre>\n",
+
+ "``` {ocaml} \nwith extra whitespace\n```\n",
+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n",
+
+ "```{ ocaml }\nwith extra whitespace\n```\n",
+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n",
+
+ "~ ~~ java\nWith whitespace\n~~~\n",
+ "<p>~ ~~ java\nWith whitespace\n~~~</p>\n",
+
+ "~~\nonly two\n~~\n",
+ "<p>~~\nonly two\n~~</p>\n",
+
+ "```` python\nextra\n````\n",
+ "<pre><code class=\"language-python\">extra\n</code></pre>\n",
+
+ "~~~ perl\nthree to start, four to end\n~~~~\n",
+ "<p>~~~ perl\nthree to start, four to end\n~~~~</p>\n",
+
+ "~~~~ perl\nfour to start, three to end\n~~~\n",
+ "<p>~~~~ perl\nfour to start, three to end\n~~~</p>\n",
+
+ "~~~ bash\ntildes\n~~~\n",
+ "<pre><code class=\"language-bash\">tildes\n</code></pre>\n",
+
+ "``` lisp\nno ending\n",
+ "<p>``` lisp\nno ending</p>\n",
+
+ "~~~ lisp\nend with language\n~~~ lisp\n",
+ "<p>~~~ lisp\nend with language\n~~~ lisp</p>\n",
+
+ "```\nmismatched begin and end\n~~~\n",
+ "<p>```\nmismatched begin and end\n~~~</p>\n",
+
+ "~~~\nmismatched begin and end\n```\n",
+ "<p>~~~\nmismatched begin and end\n```</p>\n",
+
+ " ``` oz\nleading spaces\n```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ "``` oz\nleading spaces\n ```\n",
+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n",
+
+ " ``` oz\nleading spaces\n ```\n",
+ "<pre><code>``` oz\n</code></pre>\n\n<p>leading spaces</p>\n\n<pre><code>```\n</code></pre>\n",
+ }
+ doTestsBlock(t, tests, EXTENSION_FENCED_CODE|EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
+}
+
+func TestTitleBlock_EXTENSION_TITLEBLOCK(t *testing.T) {
+ var tests = []string{
+ "% Some title\n" +
+ "% Another title line\n" +
+ "% Yep, more here too\n",
+ "<h1 class=\"title\">" +
+ "Some title\n" +
+ "Another title line\n" +
+ "Yep, more here too\n" +
+ "</h1>",
+ }
+
+ doTestsBlock(t, tests, EXTENSION_TITLEBLOCK)
+
+}
diff --git a/vendor/src/github.com/russross/blackfriday/html.go b/vendor/src/github.com/russross/blackfriday/html.go
new file mode 100644
index 0000000..3655a10
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/html.go
@@ -0,0 +1,922 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+//
+// HTML rendering backend
+//
+//
+
+package blackfriday
+
+import (
+ "bytes"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// Html renderer configuration options.
+const (
+ HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks
+ HTML_SKIP_STYLE // skip embedded <style> elements
+ HTML_SKIP_IMAGES // skip embedded images
+ HTML_SKIP_LINKS // skip all links
+ HTML_SAFELINK // only link to trusted protocols
+ HTML_NOFOLLOW_LINKS // only link with rel="nofollow"
+ HTML_NOREFERRER_LINKS // only link with rel="noreferrer"
+ HTML_HREF_TARGET_BLANK // add a blank target
+ HTML_TOC // generate a table of contents
+ HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents)
+ HTML_COMPLETE_PAGE // generate a complete HTML page
+ HTML_USE_XHTML // generate XHTML output instead of HTML
+ HTML_USE_SMARTYPANTS // enable smart punctuation substitutions
+ HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS)
+ HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS)
+ HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering
+ HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source
+)
+
+var (
+ alignments = []string{
+ "left",
+ "right",
+ "center",
+ }
+
+ // TODO: improve this regexp to catch all possible entities:
+ htmlEntity = regexp.MustCompile(`&[a-z]{2,5};`)
+)
+
+type HtmlRendererParameters struct {
+ // Prepend this text to each relative URL.
+ AbsolutePrefix string
+ // Add this text to each footnote anchor, to ensure uniqueness.
+ FootnoteAnchorPrefix string
+ // Show this text inside the <a> tag for a footnote return link, if the
+ // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string
+ // <sup>[return]</sup> is used.
+ FootnoteReturnLinkContents string
+ // If set, add this text to the front of each Header ID, to ensure
+ // uniqueness.
+ HeaderIDPrefix string
+ // If set, add this text to the back of each Header ID, to ensure uniqueness.
+ HeaderIDSuffix string
+}
+
+// Html is a type that implements the Renderer interface for HTML output.
+//
+// Do not create this directly, instead use the HtmlRenderer function.
+type Html struct {
+ flags int // HTML_* options
+ closeTag string // how to end singleton tags: either " />\n" or ">\n"
+ title string // document title
+ css string // optional css file url (used with HTML_COMPLETE_PAGE)
+
+ parameters HtmlRendererParameters
+
+ // table of contents data
+ tocMarker int
+ headerCount int
+ currentLevel int
+ toc *bytes.Buffer
+
+ // Track header IDs to prevent ID collision in a single generation.
+ headerIDs map[string]int
+
+ smartypants *smartypantsRenderer
+}
+
+const (
+ xhtmlClose = " />\n"
+ htmlClose = ">\n"
+)
+
+// HtmlRenderer creates and configures an Html object, which
+// satisfies the Renderer interface.
+//
+// flags is a set of HTML_* options ORed together.
+// title is the title of the document, and css is a URL for the document's
+// stylesheet.
+// title and css are only used when HTML_COMPLETE_PAGE is selected.
+func HtmlRenderer(flags int, title string, css string) Renderer {
+ return HtmlRendererWithParameters(flags, title, css, HtmlRendererParameters{})
+}
+
+func HtmlRendererWithParameters(flags int, title string,
+ css string, renderParameters HtmlRendererParameters) Renderer {
+ // configure the rendering engine
+ closeTag := htmlClose
+ if flags&HTML_USE_XHTML != 0 {
+ closeTag = xhtmlClose
+ }
+
+ if renderParameters.FootnoteReturnLinkContents == "" {
+ renderParameters.FootnoteReturnLinkContents = `<sup>[return]</sup>`
+ }
+
+ return &Html{
+ flags: flags,
+ closeTag: closeTag,
+ title: title,
+ css: css,
+ parameters: renderParameters,
+
+ headerCount: 0,
+ currentLevel: 0,
+ toc: new(bytes.Buffer),
+
+ headerIDs: make(map[string]int),
+
+ smartypants: smartypants(flags),
+ }
+}
+
+// Using if statements is a bit faster than a switch statement. As the compiler
+// improves, this should be unnecessary this is only worthwhile because
+// attrEscape is the single largest CPU user in normal use.
+// Also tried using map, but that gave a ~3x slowdown.
+func escapeSingleChar(char byte) (string, bool) {
+ if char == '"' {
+ return """, true
+ }
+ if char == '&' {
+ return "&", true
+ }
+ if char == '<' {
+ return "<", true
+ }
+ if char == '>' {
+ return ">", true
+ }
+ return "", false
+}
+
+func attrEscape(out *bytes.Buffer, src []byte) {
+ org := 0
+ for i, ch := range src {
+ if entity, ok := escapeSingleChar(ch); ok {
+ if i > org {
+ // copy all the normal characters since the last escape
+ out.Write(src[org:i])
+ }
+ org = i + 1
+ out.WriteString(entity)
+ }
+ }
+ if org < len(src) {
+ out.Write(src[org:])
+ }
+}
+
+func entityEscapeWithSkip(out *bytes.Buffer, src []byte, skipRanges [][]int) {
+ end := 0
+ for _, rang := range skipRanges {
+ attrEscape(out, src[end:rang[0]])
+ out.Write(src[rang[0]:rang[1]])
+ end = rang[1]
+ }
+ attrEscape(out, src[end:])
+}
+
+func (options *Html) GetFlags() int {
+ return options.flags
+}
+
+func (options *Html) TitleBlock(out *bytes.Buffer, text []byte) {
+ text = bytes.TrimPrefix(text, []byte("% "))
+ text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1)
+ out.WriteString("<h1 class=\"title\">")
+ out.Write(text)
+ out.WriteString("\n</h1>")
+}
+
+func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) {
+ marker := out.Len()
+ doubleSpace(out)
+
+ if id == "" && options.flags&HTML_TOC != 0 {
+ id = fmt.Sprintf("toc_%d", options.headerCount)
+ }
+
+ if id != "" {
+ id = options.ensureUniqueHeaderID(id)
+
+ if options.parameters.HeaderIDPrefix != "" {
+ id = options.parameters.HeaderIDPrefix + id
+ }
+
+ if options.parameters.HeaderIDSuffix != "" {
+ id = id + options.parameters.HeaderIDSuffix
+ }
+
+ out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id))
+ } else {
+ out.WriteString(fmt.Sprintf("<h%d>", level))
+ }
+
+ tocMarker := out.Len()
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+
+ // are we building a table of contents?
+ if options.flags&HTML_TOC != 0 {
+ options.TocHeaderWithAnchor(out.Bytes()[tocMarker:], level, id)
+ }
+
+ out.WriteString(fmt.Sprintf("</h%d>\n", level))
+}
+
+func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) {
+ if options.flags&HTML_SKIP_HTML != 0 {
+ return
+ }
+
+ doubleSpace(out)
+ out.Write(text)
+ out.WriteByte('\n')
+}
+
+func (options *Html) HRule(out *bytes.Buffer) {
+ doubleSpace(out)
+ out.WriteString("<hr")
+ out.WriteString(options.closeTag)
+}
+
+func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) {
+ doubleSpace(out)
+
+ // parse out the language names/classes
+ count := 0
+ for _, elt := range strings.Fields(lang) {
+ if elt[0] == '.' {
+ elt = elt[1:]
+ }
+ if len(elt) == 0 {
+ continue
+ }
+ if count == 0 {
+ out.WriteString("<pre><code class=\"language-")
+ } else {
+ out.WriteByte(' ')
+ }
+ attrEscape(out, []byte(elt))
+ count++
+ }
+
+ if count == 0 {
+ out.WriteString("<pre><code>")
+ } else {
+ out.WriteString("\">")
+ }
+
+ attrEscape(out, text)
+ out.WriteString("</code></pre>\n")
+}
+
+func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) {
+ doubleSpace(out)
+ out.WriteString("<blockquote>\n")
+ out.Write(text)
+ out.WriteString("</blockquote>\n")
+}
+
+func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
+ doubleSpace(out)
+ out.WriteString("<table>\n<thead>\n")
+ out.Write(header)
+ out.WriteString("</thead>\n\n<tbody>\n")
+ out.Write(body)
+ out.WriteString("</tbody>\n</table>\n")
+}
+
+func (options *Html) TableRow(out *bytes.Buffer, text []byte) {
+ doubleSpace(out)
+ out.WriteString("<tr>\n")
+ out.Write(text)
+ out.WriteString("\n</tr>\n")
+}
+
+func (options *Html) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
+ doubleSpace(out)
+ switch align {
+ case TABLE_ALIGNMENT_LEFT:
+ out.WriteString("<th align=\"left\">")
+ case TABLE_ALIGNMENT_RIGHT:
+ out.WriteString("<th align=\"right\">")
+ case TABLE_ALIGNMENT_CENTER:
+ out.WriteString("<th align=\"center\">")
+ default:
+ out.WriteString("<th>")
+ }
+
+ out.Write(text)
+ out.WriteString("</th>")
+}
+
+func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) {
+ doubleSpace(out)
+ switch align {
+ case TABLE_ALIGNMENT_LEFT:
+ out.WriteString("<td align=\"left\">")
+ case TABLE_ALIGNMENT_RIGHT:
+ out.WriteString("<td align=\"right\">")
+ case TABLE_ALIGNMENT_CENTER:
+ out.WriteString("<td align=\"center\">")
+ default:
+ out.WriteString("<td>")
+ }
+
+ out.Write(text)
+ out.WriteString("</td>")
+}
+
+func (options *Html) Footnotes(out *bytes.Buffer, text func() bool) {
+ out.WriteString("<div class=\"footnotes\">\n")
+ options.HRule(out)
+ options.List(out, text, LIST_TYPE_ORDERED)
+ out.WriteString("</div>\n")
+}
+
+func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
+ if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
+ doubleSpace(out)
+ }
+ slug := slugify(name)
+ out.WriteString(`<li id="`)
+ out.WriteString(`fn:`)
+ out.WriteString(options.parameters.FootnoteAnchorPrefix)
+ out.Write(slug)
+ out.WriteString(`">`)
+ out.Write(text)
+ if options.flags&HTML_FOOTNOTE_RETURN_LINKS != 0 {
+ out.WriteString(` <a class="footnote-return" href="#`)
+ out.WriteString(`fnref:`)
+ out.WriteString(options.parameters.FootnoteAnchorPrefix)
+ out.Write(slug)
+ out.WriteString(`">`)
+ out.WriteString(options.parameters.FootnoteReturnLinkContents)
+ out.WriteString(`</a>`)
+ }
+ out.WriteString("</li>\n")
+}
+
+func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) {
+ marker := out.Len()
+ doubleSpace(out)
+
+ if flags&LIST_TYPE_ORDERED != 0 {
+ out.WriteString("<ol>")
+ } else {
+ out.WriteString("<ul>")
+ }
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ if flags&LIST_TYPE_ORDERED != 0 {
+ out.WriteString("</ol>\n")
+ } else {
+ out.WriteString("</ul>\n")
+ }
+}
+
+func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) {
+ if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 {
+ doubleSpace(out)
+ }
+ out.WriteString("<li>")
+ out.Write(text)
+ out.WriteString("</li>\n")
+}
+
+func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) {
+ marker := out.Len()
+ doubleSpace(out)
+
+ out.WriteString("<p>")
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ out.WriteString("</p>\n")
+}
+
+func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) {
+ skipRanges := htmlEntity.FindAllIndex(link, -1)
+ if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) && kind != LINK_TYPE_EMAIL {
+ // mark it but don't link it if it is not a safe link: no smartypants
+ out.WriteString("<tt>")
+ entityEscapeWithSkip(out, link, skipRanges)
+ out.WriteString("</tt>")
+ return
+ }
+
+ out.WriteString("<a href=\"")
+ if kind == LINK_TYPE_EMAIL {
+ out.WriteString("mailto:")
+ } else {
+ options.maybeWriteAbsolutePrefix(out, link)
+ }
+
+ entityEscapeWithSkip(out, link, skipRanges)
+
+ var relAttrs []string
+ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
+ relAttrs = append(relAttrs, "nofollow")
+ }
+ if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
+ relAttrs = append(relAttrs, "noreferrer")
+ }
+ if len(relAttrs) > 0 {
+ out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
+ }
+
+ // blank target only add to external link
+ if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
+ out.WriteString("\" target=\"_blank")
+ }
+
+ out.WriteString("\">")
+
+ // Pretty print: if we get an email address as
+ // an actual URI, e.g. `mailto:foo@bar.com`, we don't
+ // want to print the `mailto:` prefix
+ switch {
+ case bytes.HasPrefix(link, []byte("mailto://")):
+ attrEscape(out, link[len("mailto://"):])
+ case bytes.HasPrefix(link, []byte("mailto:")):
+ attrEscape(out, link[len("mailto:"):])
+ default:
+ entityEscapeWithSkip(out, link, skipRanges)
+ }
+
+ out.WriteString("</a>")
+}
+
+func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) {
+ out.WriteString("<code>")
+ attrEscape(out, text)
+ out.WriteString("</code>")
+}
+
+func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("<strong>")
+ out.Write(text)
+ out.WriteString("</strong>")
+}
+
+func (options *Html) Emphasis(out *bytes.Buffer, text []byte) {
+ if len(text) == 0 {
+ return
+ }
+ out.WriteString("<em>")
+ out.Write(text)
+ out.WriteString("</em>")
+}
+
+func (options *Html) maybeWriteAbsolutePrefix(out *bytes.Buffer, link []byte) {
+ if options.parameters.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' {
+ out.WriteString(options.parameters.AbsolutePrefix)
+ if link[0] != '/' {
+ out.WriteByte('/')
+ }
+ }
+}
+
+func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
+ if options.flags&HTML_SKIP_IMAGES != 0 {
+ return
+ }
+
+ out.WriteString("<img src=\"")
+ options.maybeWriteAbsolutePrefix(out, link)
+ attrEscape(out, link)
+ out.WriteString("\" alt=\"")
+ if len(alt) > 0 {
+ attrEscape(out, alt)
+ }
+ if len(title) > 0 {
+ out.WriteString("\" title=\"")
+ attrEscape(out, title)
+ }
+
+ out.WriteByte('"')
+ out.WriteString(options.closeTag)
+ return
+}
+
+func (options *Html) LineBreak(out *bytes.Buffer) {
+ out.WriteString("<br")
+ out.WriteString(options.closeTag)
+}
+
+func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
+ if options.flags&HTML_SKIP_LINKS != 0 {
+ // write the link text out but don't link it, just mark it with typewriter font
+ out.WriteString("<tt>")
+ attrEscape(out, content)
+ out.WriteString("</tt>")
+ return
+ }
+
+ if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) {
+ // write the link text out but don't link it, just mark it with typewriter font
+ out.WriteString("<tt>")
+ attrEscape(out, content)
+ out.WriteString("</tt>")
+ return
+ }
+
+ out.WriteString("<a href=\"")
+ options.maybeWriteAbsolutePrefix(out, link)
+ attrEscape(out, link)
+ if len(title) > 0 {
+ out.WriteString("\" title=\"")
+ attrEscape(out, title)
+ }
+ var relAttrs []string
+ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) {
+ relAttrs = append(relAttrs, "nofollow")
+ }
+ if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) {
+ relAttrs = append(relAttrs, "noreferrer")
+ }
+ if len(relAttrs) > 0 {
+ out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " ")))
+ }
+
+ // blank target only add to external link
+ if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) {
+ out.WriteString("\" target=\"_blank")
+ }
+
+ out.WriteString("\">")
+ out.Write(content)
+ out.WriteString("</a>")
+ return
+}
+
+func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) {
+ if options.flags&HTML_SKIP_HTML != 0 {
+ return
+ }
+ if options.flags&HTML_SKIP_STYLE != 0 && isHtmlTag(text, "style") {
+ return
+ }
+ if options.flags&HTML_SKIP_LINKS != 0 && isHtmlTag(text, "a") {
+ return
+ }
+ if options.flags&HTML_SKIP_IMAGES != 0 && isHtmlTag(text, "img") {
+ return
+ }
+ out.Write(text)
+}
+
+func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("<strong><em>")
+ out.Write(text)
+ out.WriteString("</em></strong>")
+}
+
+func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) {
+ out.WriteString("<del>")
+ out.Write(text)
+ out.WriteString("</del>")
+}
+
+func (options *Html) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
+ slug := slugify(ref)
+ out.WriteString(`<sup class="footnote-ref" id="`)
+ out.WriteString(`fnref:`)
+ out.WriteString(options.parameters.FootnoteAnchorPrefix)
+ out.Write(slug)
+ out.WriteString(`"><a rel="footnote" href="#`)
+ out.WriteString(`fn:`)
+ out.WriteString(options.parameters.FootnoteAnchorPrefix)
+ out.Write(slug)
+ out.WriteString(`">`)
+ out.WriteString(strconv.Itoa(id))
+ out.WriteString(`</a></sup>`)
+}
+
+func (options *Html) Entity(out *bytes.Buffer, entity []byte) {
+ out.Write(entity)
+}
+
+func (options *Html) NormalText(out *bytes.Buffer, text []byte) {
+ if options.flags&HTML_USE_SMARTYPANTS != 0 {
+ options.Smartypants(out, text)
+ } else {
+ attrEscape(out, text)
+ }
+}
+
+func (options *Html) Smartypants(out *bytes.Buffer, text []byte) {
+ smrt := smartypantsData{false, false}
+
+ // first do normal entity escaping
+ var escaped bytes.Buffer
+ attrEscape(&escaped, text)
+ text = escaped.Bytes()
+
+ mark := 0
+ for i := 0; i < len(text); i++ {
+ if action := options.smartypants[text[i]]; action != nil {
+ if i > mark {
+ out.Write(text[mark:i])
+ }
+
+ previousChar := byte(0)
+ if i > 0 {
+ previousChar = text[i-1]
+ }
+ i += action(out, &smrt, previousChar, text[i:])
+ mark = i + 1
+ }
+ }
+
+ if mark < len(text) {
+ out.Write(text[mark:])
+ }
+}
+
+func (options *Html) DocumentHeader(out *bytes.Buffer) {
+ if options.flags&HTML_COMPLETE_PAGE == 0 {
+ return
+ }
+
+ ending := ""
+ if options.flags&HTML_USE_XHTML != 0 {
+ out.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ")
+ out.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n")
+ out.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n")
+ ending = " /"
+ } else {
+ out.WriteString("<!DOCTYPE html>\n")
+ out.WriteString("<html>\n")
+ }
+ out.WriteString("<head>\n")
+ out.WriteString(" <title>")
+ options.NormalText(out, []byte(options.title))
+ out.WriteString("</title>\n")
+ out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v")
+ out.WriteString(VERSION)
+ out.WriteString("\"")
+ out.WriteString(ending)
+ out.WriteString(">\n")
+ out.WriteString(" <meta charset=\"utf-8\"")
+ out.WriteString(ending)
+ out.WriteString(">\n")
+ if options.css != "" {
+ out.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")
+ attrEscape(out, []byte(options.css))
+ out.WriteString("\"")
+ out.WriteString(ending)
+ out.WriteString(">\n")
+ }
+ out.WriteString("</head>\n")
+ out.WriteString("<body>\n")
+
+ options.tocMarker = out.Len()
+}
+
+func (options *Html) DocumentFooter(out *bytes.Buffer) {
+ // finalize and insert the table of contents
+ if options.flags&HTML_TOC != 0 {
+ options.TocFinalize()
+
+ // now we have to insert the table of contents into the document
+ var temp bytes.Buffer
+
+ // start by making a copy of everything after the document header
+ temp.Write(out.Bytes()[options.tocMarker:])
+
+ // now clear the copied material from the main output buffer
+ out.Truncate(options.tocMarker)
+
+ // corner case spacing issue
+ if options.flags&HTML_COMPLETE_PAGE != 0 {
+ out.WriteByte('\n')
+ }
+
+ // insert the table of contents
+ out.WriteString("<nav>\n")
+ out.Write(options.toc.Bytes())
+ out.WriteString("</nav>\n")
+
+ // corner case spacing issue
+ if options.flags&HTML_COMPLETE_PAGE == 0 && options.flags&HTML_OMIT_CONTENTS == 0 {
+ out.WriteByte('\n')
+ }
+
+ // write out everything that came after it
+ if options.flags&HTML_OMIT_CONTENTS == 0 {
+ out.Write(temp.Bytes())
+ }
+ }
+
+ if options.flags&HTML_COMPLETE_PAGE != 0 {
+ out.WriteString("\n</body>\n")
+ out.WriteString("</html>\n")
+ }
+
+}
+
+func (options *Html) TocHeaderWithAnchor(text []byte, level int, anchor string) {
+ for level > options.currentLevel {
+ switch {
+ case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")):
+ // this sublist can nest underneath a header
+ size := options.toc.Len()
+ options.toc.Truncate(size - len("</li>\n"))
+
+ case options.currentLevel > 0:
+ options.toc.WriteString("<li>")
+ }
+ if options.toc.Len() > 0 {
+ options.toc.WriteByte('\n')
+ }
+ options.toc.WriteString("<ul>\n")
+ options.currentLevel++
+ }
+
+ for level < options.currentLevel {
+ options.toc.WriteString("</ul>")
+ if options.currentLevel > 1 {
+ options.toc.WriteString("</li>\n")
+ }
+ options.currentLevel--
+ }
+
+ options.toc.WriteString("<li><a href=\"#")
+ if anchor != "" {
+ options.toc.WriteString(anchor)
+ } else {
+ options.toc.WriteString("toc_")
+ options.toc.WriteString(strconv.Itoa(options.headerCount))
+ }
+ options.toc.WriteString("\">")
+ options.headerCount++
+
+ options.toc.Write(text)
+
+ options.toc.WriteString("</a></li>\n")
+}
+
+func (options *Html) TocHeader(text []byte, level int) {
+ options.TocHeaderWithAnchor(text, level, "")
+}
+
+func (options *Html) TocFinalize() {
+ for options.currentLevel > 1 {
+ options.toc.WriteString("</ul></li>\n")
+ options.currentLevel--
+ }
+
+ if options.currentLevel > 0 {
+ options.toc.WriteString("</ul>\n")
+ }
+}
+
+func isHtmlTag(tag []byte, tagname string) bool {
+ found, _ := findHtmlTagPos(tag, tagname)
+ return found
+}
+
+// Look for a character, but ignore it when it's in any kind of quotes, it
+// might be JavaScript
+func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int {
+ inSingleQuote := false
+ inDoubleQuote := false
+ inGraveQuote := false
+ i := start
+ for i < len(html) {
+ switch {
+ case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote:
+ return i
+ case html[i] == '\'':
+ inSingleQuote = !inSingleQuote
+ case html[i] == '"':
+ inDoubleQuote = !inDoubleQuote
+ case html[i] == '`':
+ inGraveQuote = !inGraveQuote
+ }
+ i++
+ }
+ return start
+}
+
+func findHtmlTagPos(tag []byte, tagname string) (bool, int) {
+ i := 0
+ if i < len(tag) && tag[0] != '<' {
+ return false, -1
+ }
+ i++
+ i = skipSpace(tag, i)
+
+ if i < len(tag) && tag[i] == '/' {
+ i++
+ }
+
+ i = skipSpace(tag, i)
+ j := 0
+ for ; i < len(tag); i, j = i+1, j+1 {
+ if j >= len(tagname) {
+ break
+ }
+
+ if strings.ToLower(string(tag[i]))[0] != tagname[j] {
+ return false, -1
+ }
+ }
+
+ if i == len(tag) {
+ return false, -1
+ }
+
+ rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>')
+ if rightAngle > i {
+ return true, rightAngle
+ }
+
+ return false, -1
+}
+
+func skipUntilChar(text []byte, start int, char byte) int {
+ i := start
+ for i < len(text) && text[i] != char {
+ i++
+ }
+ return i
+}
+
+func skipSpace(tag []byte, i int) int {
+ for i < len(tag) && isspace(tag[i]) {
+ i++
+ }
+ return i
+}
+
+func doubleSpace(out *bytes.Buffer) {
+ if out.Len() > 0 {
+ out.WriteByte('\n')
+ }
+}
+
+func isRelativeLink(link []byte) (yes bool) {
+ // a tag begin with '#'
+ if link[0] == '#' {
+ return true
+ }
+
+ // link begin with '/' but not '//', the second maybe a protocol relative link
+ if len(link) >= 2 && link[0] == '/' && link[1] != '/' {
+ return true
+ }
+
+ // only the root '/'
+ if len(link) == 1 && link[0] == '/' {
+ return true
+ }
+
+ // current directory : begin with "./"
+ if bytes.HasPrefix(link, []byte("./")) {
+ return true
+ }
+
+ // parent directory : begin with "../"
+ if bytes.HasPrefix(link, []byte("../")) {
+ return true
+ }
+
+ return false
+}
+
+func (options *Html) ensureUniqueHeaderID(id string) string {
+ for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] {
+ tmp := fmt.Sprintf("%s-%d", id, count+1)
+
+ if _, tmpFound := options.headerIDs[tmp]; !tmpFound {
+ options.headerIDs[id] = count + 1
+ id = tmp
+ } else {
+ id = id + "-1"
+ }
+ }
+
+ if _, found := options.headerIDs[id]; !found {
+ options.headerIDs[id] = 0
+ }
+
+ return id
+}
diff --git a/vendor/src/github.com/russross/blackfriday/inline.go b/vendor/src/github.com/russross/blackfriday/inline.go
new file mode 100644
index 0000000..b3ec847
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/inline.go
@@ -0,0 +1,1096 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Functions to parse inline elements.
+//
+
+package blackfriday
+
+import (
+ "bytes"
+ "regexp"
+ "strconv"
+)
+
+var (
+ urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+`
+ anchorRe = regexp.MustCompile(`^(<a\shref="` + urlRe + `"(\stitle="[^"<>]+")?\s?>` + urlRe + `<\/a>)`)
+)
+
+// Functions to parse text within a block
+// Each function returns the number of chars taken care of
+// data is the complete block being rendered
+// offset is the number of valid chars before the current cursor
+
+func (p *parser) inline(out *bytes.Buffer, data []byte) {
+ // this is called recursively: enforce a maximum depth
+ if p.nesting >= p.maxNesting {
+ return
+ }
+ p.nesting++
+
+ i, end := 0, 0
+ for i < len(data) {
+ // copy inactive chars into the output
+ for end < len(data) && p.inlineCallback[data[end]] == nil {
+ end++
+ }
+
+ p.r.NormalText(out, data[i:end])
+
+ if end >= len(data) {
+ break
+ }
+ i = end
+
+ // call the trigger
+ handler := p.inlineCallback[data[end]]
+ if consumed := handler(p, out, data, i); consumed == 0 {
+ // no action from the callback; buffer the byte for later
+ end = i + 1
+ } else {
+ // skip past whatever the callback used
+ i += consumed
+ end = i
+ }
+ }
+
+ p.nesting--
+}
+
+// single and double emphasis parsing
+func emphasis(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ data = data[offset:]
+ c := data[0]
+ ret := 0
+
+ if len(data) > 2 && data[1] != c {
+ // whitespace cannot follow an opening emphasis;
+ // strikethrough only takes two characters '~~'
+ if c == '~' || isspace(data[1]) {
+ return 0
+ }
+ if ret = helperEmphasis(p, out, data[1:], c); ret == 0 {
+ return 0
+ }
+
+ return ret + 1
+ }
+
+ if len(data) > 3 && data[1] == c && data[2] != c {
+ if isspace(data[2]) {
+ return 0
+ }
+ if ret = helperDoubleEmphasis(p, out, data[2:], c); ret == 0 {
+ return 0
+ }
+
+ return ret + 2
+ }
+
+ if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c {
+ if c == '~' || isspace(data[3]) {
+ return 0
+ }
+ if ret = helperTripleEmphasis(p, out, data, 3, c); ret == 0 {
+ return 0
+ }
+
+ return ret + 3
+ }
+
+ return 0
+}
+
+func codeSpan(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ data = data[offset:]
+
+ nb := 0
+
+ // count the number of backticks in the delimiter
+ for nb < len(data) && data[nb] == '`' {
+ nb++
+ }
+
+ // find the next delimiter
+ i, end := 0, 0
+ for end = nb; end < len(data) && i < nb; end++ {
+ if data[end] == '`' {
+ i++
+ } else {
+ i = 0
+ }
+ }
+
+ // no matching delimiter?
+ if i < nb && end >= len(data) {
+ return 0
+ }
+
+ // trim outside whitespace
+ fBegin := nb
+ for fBegin < end && data[fBegin] == ' ' {
+ fBegin++
+ }
+
+ fEnd := end - nb
+ for fEnd > fBegin && data[fEnd-1] == ' ' {
+ fEnd--
+ }
+
+ // render the code span
+ if fBegin != fEnd {
+ p.r.CodeSpan(out, data[fBegin:fEnd])
+ }
+
+ return end
+
+}
+
+// newline preceded by two spaces becomes <br>
+// newline without two spaces works when EXTENSION_HARD_LINE_BREAK is enabled
+func lineBreak(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ // remove trailing spaces from out
+ outBytes := out.Bytes()
+ end := len(outBytes)
+ eol := end
+ for eol > 0 && outBytes[eol-1] == ' ' {
+ eol--
+ }
+ out.Truncate(eol)
+
+ precededByTwoSpaces := offset >= 2 && data[offset-2] == ' ' && data[offset-1] == ' '
+ precededByBackslash := offset >= 1 && data[offset-1] == '\\' // see http://spec.commonmark.org/0.18/#example-527
+ precededByBackslash = precededByBackslash && p.flags&EXTENSION_BACKSLASH_LINE_BREAK != 0
+
+ // should there be a hard line break here?
+ if p.flags&EXTENSION_HARD_LINE_BREAK == 0 && !precededByTwoSpaces && !precededByBackslash {
+ return 0
+ }
+
+ if precededByBackslash && eol > 0 {
+ out.Truncate(eol - 1)
+ }
+ p.r.LineBreak(out)
+ return 1
+}
+
+type linkType int
+
+const (
+ linkNormal linkType = iota
+ linkImg
+ linkDeferredFootnote
+ linkInlineFootnote
+)
+
+// '[': parse a link or an image or a footnote
+func link(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ // no links allowed inside regular links, footnote, and deferred footnotes
+ if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') {
+ return 0
+ }
+
+ // [text] == regular link
+ // ![alt] == image
+ // ^[text] == inline footnote
+ // [^refId] == deferred footnote
+ var t linkType
+ if offset > 0 && data[offset-1] == '!' {
+ t = linkImg
+ } else if p.flags&EXTENSION_FOOTNOTES != 0 {
+ if offset > 0 && data[offset-1] == '^' {
+ t = linkInlineFootnote
+ } else if len(data)-1 > offset && data[offset+1] == '^' {
+ t = linkDeferredFootnote
+ }
+ }
+
+ data = data[offset:]
+
+ var (
+ i = 1
+ noteId int
+ title, link []byte
+ textHasNl = false
+ )
+
+ if t == linkDeferredFootnote {
+ i++
+ }
+
+ // look for the matching closing bracket
+ for level := 1; level > 0 && i < len(data); i++ {
+ switch {
+ case data[i] == '\n':
+ textHasNl = true
+
+ case data[i-1] == '\\':
+ continue
+
+ case data[i] == '[':
+ level++
+
+ case data[i] == ']':
+ level--
+ if level <= 0 {
+ i-- // compensate for extra i++ in for loop
+ }
+ }
+ }
+
+ if i >= len(data) {
+ return 0
+ }
+
+ txtE := i
+ i++
+
+ // skip any amount of whitespace or newline
+ // (this is much more lax than original markdown syntax)
+ for i < len(data) && isspace(data[i]) {
+ i++
+ }
+
+ // inline style link
+ switch {
+ case i < len(data) && data[i] == '(':
+ // skip initial whitespace
+ i++
+
+ for i < len(data) && isspace(data[i]) {
+ i++
+ }
+
+ linkB := i
+
+ // look for link end: ' " )
+ findlinkend:
+ for i < len(data) {
+ switch {
+ case data[i] == '\\':
+ i += 2
+
+ case data[i] == ')' || data[i] == '\'' || data[i] == '"':
+ break findlinkend
+
+ default:
+ i++
+ }
+ }
+
+ if i >= len(data) {
+ return 0
+ }
+ linkE := i
+
+ // look for title end if present
+ titleB, titleE := 0, 0
+ if data[i] == '\'' || data[i] == '"' {
+ i++
+ titleB = i
+
+ findtitleend:
+ for i < len(data) {
+ switch {
+ case data[i] == '\\':
+ i += 2
+
+ case data[i] == ')':
+ break findtitleend
+
+ default:
+ i++
+ }
+ }
+
+ if i >= len(data) {
+ return 0
+ }
+
+ // skip whitespace after title
+ titleE = i - 1
+ for titleE > titleB && isspace(data[titleE]) {
+ titleE--
+ }
+
+ // check for closing quote presence
+ if data[titleE] != '\'' && data[titleE] != '"' {
+ titleB, titleE = 0, 0
+ linkE = i
+ }
+ }
+
+ // remove whitespace at the end of the link
+ for linkE > linkB && isspace(data[linkE-1]) {
+ linkE--
+ }
+
+ // remove optional angle brackets around the link
+ if data[linkB] == '<' {
+ linkB++
+ }
+ if data[linkE-1] == '>' {
+ linkE--
+ }
+
+ // build escaped link and title
+ if linkE > linkB {
+ link = data[linkB:linkE]
+ }
+
+ if titleE > titleB {
+ title = data[titleB:titleE]
+ }
+
+ i++
+
+ // reference style link
+ case i < len(data)-1 && data[i] == '[' && data[i+1] != '^':
+ var id []byte
+
+ // look for the id
+ i++
+ linkB := i
+ for i < len(data) && data[i] != ']' {
+ i++
+ }
+ if i >= len(data) {
+ return 0
+ }
+ linkE := i
+
+ // find the reference
+ if linkB == linkE {
+ if textHasNl {
+ var b bytes.Buffer
+
+ for j := 1; j < txtE; j++ {
+ switch {
+ case data[j] != '\n':
+ b.WriteByte(data[j])
+ case data[j-1] != ' ':
+ b.WriteByte(' ')
+ }
+ }
+
+ id = b.Bytes()
+ } else {
+ id = data[1:txtE]
+ }
+ } else {
+ id = data[linkB:linkE]
+ }
+
+ // find the reference with matching id (ids are case-insensitive)
+ key := string(bytes.ToLower(id))
+ lr, ok := p.refs[key]
+ if !ok {
+ return 0
+
+ }
+
+ // keep link and title from reference
+ link = lr.link
+ title = lr.title
+ i++
+
+ // shortcut reference style link or reference or inline footnote
+ default:
+ var id []byte
+
+ // craft the id
+ if textHasNl {
+ var b bytes.Buffer
+
+ for j := 1; j < txtE; j++ {
+ switch {
+ case data[j] != '\n':
+ b.WriteByte(data[j])
+ case data[j-1] != ' ':
+ b.WriteByte(' ')
+ }
+ }
+
+ id = b.Bytes()
+ } else {
+ if t == linkDeferredFootnote {
+ id = data[2:txtE] // get rid of the ^
+ } else {
+ id = data[1:txtE]
+ }
+ }
+
+ key := string(bytes.ToLower(id))
+ if t == linkInlineFootnote {
+ // create a new reference
+ noteId = len(p.notes) + 1
+
+ var fragment []byte
+ if len(id) > 0 {
+ if len(id) < 16 {
+ fragment = make([]byte, len(id))
+ } else {
+ fragment = make([]byte, 16)
+ }
+ copy(fragment, slugify(id))
+ } else {
+ fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteId))...)
+ }
+
+ ref := &reference{
+ noteId: noteId,
+ hasBlock: false,
+ link: fragment,
+ title: id,
+ }
+
+ p.notes = append(p.notes, ref)
+
+ link = ref.link
+ title = ref.title
+ } else {
+ // find the reference with matching id
+ lr, ok := p.refs[key]
+ if !ok {
+ return 0
+ }
+
+ if t == linkDeferredFootnote {
+ lr.noteId = len(p.notes) + 1
+ p.notes = append(p.notes, lr)
+ }
+
+ // keep link and title from reference
+ link = lr.link
+ // if inline footnote, title == footnote contents
+ title = lr.title
+ noteId = lr.noteId
+ }
+
+ // rewind the whitespace
+ i = txtE + 1
+ }
+
+ // build content: img alt is escaped, link content is parsed
+ var content bytes.Buffer
+ if txtE > 1 {
+ if t == linkImg {
+ content.Write(data[1:txtE])
+ } else {
+ // links cannot contain other links, so turn off link parsing temporarily
+ insideLink := p.insideLink
+ p.insideLink = true
+ p.inline(&content, data[1:txtE])
+ p.insideLink = insideLink
+ }
+ }
+
+ var uLink []byte
+ if t == linkNormal || t == linkImg {
+ if len(link) > 0 {
+ var uLinkBuf bytes.Buffer
+ unescapeText(&uLinkBuf, link)
+ uLink = uLinkBuf.Bytes()
+ }
+
+ // links need something to click on and somewhere to go
+ if len(uLink) == 0 || (t == linkNormal && content.Len() == 0) {
+ return 0
+ }
+ }
+
+ // call the relevant rendering function
+ switch t {
+ case linkNormal:
+ p.r.Link(out, uLink, title, content.Bytes())
+
+ case linkImg:
+ outSize := out.Len()
+ outBytes := out.Bytes()
+ if outSize > 0 && outBytes[outSize-1] == '!' {
+ out.Truncate(outSize - 1)
+ }
+
+ p.r.Image(out, uLink, title, content.Bytes())
+
+ case linkInlineFootnote:
+ outSize := out.Len()
+ outBytes := out.Bytes()
+ if outSize > 0 && outBytes[outSize-1] == '^' {
+ out.Truncate(outSize - 1)
+ }
+
+ p.r.FootnoteRef(out, link, noteId)
+
+ case linkDeferredFootnote:
+ p.r.FootnoteRef(out, link, noteId)
+
+ default:
+ return 0
+ }
+
+ return i
+}
+
+// '<' when tags or autolinks are allowed
+func leftAngle(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ data = data[offset:]
+ altype := LINK_TYPE_NOT_AUTOLINK
+ end := tagLength(data, &altype)
+
+ if end > 2 {
+ if altype != LINK_TYPE_NOT_AUTOLINK {
+ var uLink bytes.Buffer
+ unescapeText(&uLink, data[1:end+1-2])
+ if uLink.Len() > 0 {
+ p.r.AutoLink(out, uLink.Bytes(), altype)
+ }
+ } else {
+ p.r.RawHtmlTag(out, data[:end])
+ }
+ }
+
+ return end
+}
+
+// '\\' backslash escape
+var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~")
+
+func escape(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ data = data[offset:]
+
+ if len(data) > 1 {
+ if bytes.IndexByte(escapeChars, data[1]) < 0 {
+ return 0
+ }
+
+ p.r.NormalText(out, data[1:2])
+ }
+
+ return 2
+}
+
+func unescapeText(ob *bytes.Buffer, src []byte) {
+ i := 0
+ for i < len(src) {
+ org := i
+ for i < len(src) && src[i] != '\\' {
+ i++
+ }
+
+ if i > org {
+ ob.Write(src[org:i])
+ }
+
+ if i+1 >= len(src) {
+ break
+ }
+
+ ob.WriteByte(src[i+1])
+ i += 2
+ }
+}
+
+// '&' escaped when it doesn't belong to an entity
+// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+;
+func entity(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ data = data[offset:]
+
+ end := 1
+
+ if end < len(data) && data[end] == '#' {
+ end++
+ }
+
+ for end < len(data) && isalnum(data[end]) {
+ end++
+ }
+
+ if end < len(data) && data[end] == ';' {
+ end++ // real entity
+ } else {
+ return 0 // lone '&'
+ }
+
+ p.r.Entity(out, data[:end])
+
+ return end
+}
+
+func linkEndsWithEntity(data []byte, linkEnd int) bool {
+ entityRanges := htmlEntity.FindAllIndex(data[:linkEnd], -1)
+ if entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd {
+ return true
+ }
+ return false
+}
+
+func autoLink(p *parser, out *bytes.Buffer, data []byte, offset int) int {
+ // quick check to rule out most false hits on ':'
+ if p.insideLink || len(data) < offset+3 || data[offset+1] != '/' || data[offset+2] != '/' {
+ return 0
+ }
+
+ // Now a more expensive check to see if we're not inside an anchor element
+ anchorStart := offset
+ offsetFromAnchor := 0
+ for anchorStart > 0 && data[anchorStart] != '<' {
+ anchorStart--
+ offsetFromAnchor++
+ }
+
+ anchorStr := anchorRe.Find(data[anchorStart:])
+ if anchorStr != nil {
+ out.Write(anchorStr[offsetFromAnchor:])
+ return len(anchorStr) - offsetFromAnchor
+ }
+
+ // scan backward for a word boundary
+ rewind := 0
+ for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) {
+ rewind++
+ }
+ if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters
+ return 0
+ }
+
+ origData := data
+ data = data[offset-rewind:]
+
+ if !isSafeLink(data) {
+ return 0
+ }
+
+ linkEnd := 0
+ for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) {
+ linkEnd++
+ }
+
+ // Skip punctuation at the end of the link
+ if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' {
+ linkEnd--
+ }
+
+ // But don't skip semicolon if it's a part of escaped entity:
+ if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) {
+ linkEnd--
+ }
+
+ // See if the link finishes with a punctuation sign that can be closed.
+ var copen byte
+ switch data[linkEnd-1] {
+ case '"':
+ copen = '"'
+ case '\'':
+ copen = '\''
+ case ')':
+ copen = '('
+ case ']':
+ copen = '['
+ case '}':
+ copen = '{'
+ default:
+ copen = 0
+ }
+
+ if copen != 0 {
+ bufEnd := offset - rewind + linkEnd - 2
+
+ openDelim := 1
+
+ /* Try to close the final punctuation sign in this same line;
+ * if we managed to close it outside of the URL, that means that it's
+ * not part of the URL. If it closes inside the URL, that means it
+ * is part of the URL.
+ *
+ * Examples:
+ *
+ * foo http://www.pokemon.com/Pikachu_(Electric) bar
+ * => http://www.pokemon.com/Pikachu_(Electric)
+ *
+ * foo (http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => http://www.pokemon.com/Pikachu_(Electric)
+ *
+ * foo http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => http://www.pokemon.com/Pikachu_(Electric))
+ *
+ * (foo http://www.pokemon.com/Pikachu_(Electric)) bar
+ * => foo http://www.pokemon.com/Pikachu_(Electric)
+ */
+
+ for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 {
+ if origData[bufEnd] == data[linkEnd-1] {
+ openDelim++
+ }
+
+ if origData[bufEnd] == copen {
+ openDelim--
+ }
+
+ bufEnd--
+ }
+
+ if openDelim == 0 {
+ linkEnd--
+ }
+ }
+
+ // we were triggered on the ':', so we need to rewind the output a bit
+ if out.Len() >= rewind {
+ out.Truncate(len(out.Bytes()) - rewind)
+ }
+
+ var uLink bytes.Buffer
+ unescapeText(&uLink, data[:linkEnd])
+
+ if uLink.Len() > 0 {
+ p.r.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL)
+ }
+
+ return linkEnd - rewind
+}
+
+func isEndOfLink(char byte) bool {
+ return isspace(char) || char == '<'
+}
+
+var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")}
+var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")}
+
+func isSafeLink(link []byte) bool {
+ for _, path := range validPaths {
+ if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) {
+ if len(link) == len(path) {
+ return true
+ } else if isalnum(link[len(path)]) {
+ return true
+ }
+ }
+ }
+
+ for _, prefix := range validUris {
+ // TODO: handle unicode here
+ // case-insensitive prefix test
+ if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) {
+ return true
+ }
+ }
+
+ return false
+}
+
+// return the length of the given tag, or 0 is it's not valid
+func tagLength(data []byte, autolink *int) int {
+ var i, j int
+
+ // a valid tag can't be shorter than 3 chars
+ if len(data) < 3 {
+ return 0
+ }
+
+ // begins with a '<' optionally followed by '/', followed by letter or number
+ if data[0] != '<' {
+ return 0
+ }
+ if data[1] == '/' {
+ i = 2
+ } else {
+ i = 1
+ }
+
+ if !isalnum(data[i]) {
+ return 0
+ }
+
+ // scheme test
+ *autolink = LINK_TYPE_NOT_AUTOLINK
+
+ // try to find the beginning of an URI
+ for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') {
+ i++
+ }
+
+ if i > 1 && i < len(data) && data[i] == '@' {
+ if j = isMailtoAutoLink(data[i:]); j != 0 {
+ *autolink = LINK_TYPE_EMAIL
+ return i + j
+ }
+ }
+
+ if i > 2 && i < len(data) && data[i] == ':' {
+ *autolink = LINK_TYPE_NORMAL
+ i++
+ }
+
+ // complete autolink test: no whitespace or ' or "
+ switch {
+ case i >= len(data):
+ *autolink = LINK_TYPE_NOT_AUTOLINK
+ case *autolink != 0:
+ j = i
+
+ for i < len(data) {
+ if data[i] == '\\' {
+ i += 2
+ } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) {
+ break
+ } else {
+ i++
+ }
+
+ }
+
+ if i >= len(data) {
+ return 0
+ }
+ if i > j && data[i] == '>' {
+ return i + 1
+ }
+
+ // one of the forbidden chars has been found
+ *autolink = LINK_TYPE_NOT_AUTOLINK
+ }
+
+ // look for something looking like a tag end
+ for i < len(data) && data[i] != '>' {
+ i++
+ }
+ if i >= len(data) {
+ return 0
+ }
+ return i + 1
+}
+
+// look for the address part of a mail autolink and '>'
+// this is less strict than the original markdown e-mail address matching
+func isMailtoAutoLink(data []byte) int {
+ nb := 0
+
+ // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@'
+ for i := 0; i < len(data); i++ {
+ if isalnum(data[i]) {
+ continue
+ }
+
+ switch data[i] {
+ case '@':
+ nb++
+
+ case '-', '.', '_':
+ break
+
+ case '>':
+ if nb == 1 {
+ return i + 1
+ } else {
+ return 0
+ }
+ default:
+ return 0
+ }
+ }
+
+ return 0
+}
+
+// look for the next emph char, skipping other constructs
+func helperFindEmphChar(data []byte, c byte) int {
+ i := 1
+
+ for i < len(data) {
+ for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' {
+ i++
+ }
+ if i >= len(data) {
+ return 0
+ }
+ if data[i] == c {
+ return i
+ }
+
+ // do not count escaped chars
+ if i != 0 && data[i-1] == '\\' {
+ i++
+ continue
+ }
+
+ if data[i] == '`' {
+ // skip a code span
+ tmpI := 0
+ i++
+ for i < len(data) && data[i] != '`' {
+ if tmpI == 0 && data[i] == c {
+ tmpI = i
+ }
+ i++
+ }
+ if i >= len(data) {
+ return tmpI
+ }
+ i++
+ } else if data[i] == '[' {
+ // skip a link
+ tmpI := 0
+ i++
+ for i < len(data) && data[i] != ']' {
+ if tmpI == 0 && data[i] == c {
+ tmpI = i
+ }
+ i++
+ }
+ i++
+ for i < len(data) && (data[i] == ' ' || data[i] == '\n') {
+ i++
+ }
+ if i >= len(data) {
+ return tmpI
+ }
+ if data[i] != '[' && data[i] != '(' { // not a link
+ if tmpI > 0 {
+ return tmpI
+ } else {
+ continue
+ }
+ }
+ cc := data[i]
+ i++
+ for i < len(data) && data[i] != cc {
+ if tmpI == 0 && data[i] == c {
+ return i
+ }
+ i++
+ }
+ if i >= len(data) {
+ return tmpI
+ }
+ i++
+ }
+ }
+ return 0
+}
+
+func helperEmphasis(p *parser, out *bytes.Buffer, data []byte, c byte) int {
+ i := 0
+
+ // skip one symbol if coming from emph3
+ if len(data) > 1 && data[0] == c && data[1] == c {
+ i = 1
+ }
+
+ for i < len(data) {
+ length := helperFindEmphChar(data[i:], c)
+ if length == 0 {
+ return 0
+ }
+ i += length
+ if i >= len(data) {
+ return 0
+ }
+
+ if i+1 < len(data) && data[i+1] == c {
+ i++
+ continue
+ }
+
+ if data[i] == c && !isspace(data[i-1]) {
+
+ if p.flags&EXTENSION_NO_INTRA_EMPHASIS != 0 {
+ if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) {
+ continue
+ }
+ }
+
+ var work bytes.Buffer
+ p.inline(&work, data[:i])
+ p.r.Emphasis(out, work.Bytes())
+ return i + 1
+ }
+ }
+
+ return 0
+}
+
+func helperDoubleEmphasis(p *parser, out *bytes.Buffer, data []byte, c byte) int {
+ i := 0
+
+ for i < len(data) {
+ length := helperFindEmphChar(data[i:], c)
+ if length == 0 {
+ return 0
+ }
+ i += length
+
+ if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) {
+ var work bytes.Buffer
+ p.inline(&work, data[:i])
+
+ if work.Len() > 0 {
+ // pick the right renderer
+ if c == '~' {
+ p.r.StrikeThrough(out, work.Bytes())
+ } else {
+ p.r.DoubleEmphasis(out, work.Bytes())
+ }
+ }
+ return i + 2
+ }
+ i++
+ }
+ return 0
+}
+
+func helperTripleEmphasis(p *parser, out *bytes.Buffer, data []byte, offset int, c byte) int {
+ i := 0
+ origData := data
+ data = data[offset:]
+
+ for i < len(data) {
+ length := helperFindEmphChar(data[i:], c)
+ if length == 0 {
+ return 0
+ }
+ i += length
+
+ // skip whitespace preceded symbols
+ if data[i] != c || isspace(data[i-1]) {
+ continue
+ }
+
+ switch {
+ case i+2 < len(data) && data[i+1] == c && data[i+2] == c:
+ // triple symbol found
+ var work bytes.Buffer
+
+ p.inline(&work, data[:i])
+ if work.Len() > 0 {
+ p.r.TripleEmphasis(out, work.Bytes())
+ }
+ return i + 3
+ case (i+1 < len(data) && data[i+1] == c):
+ // double symbol found, hand over to emph1
+ length = helperEmphasis(p, out, origData[offset-2:], c)
+ if length == 0 {
+ return 0
+ } else {
+ return length - 2
+ }
+ default:
+ // single symbol found, hand over to emph2
+ length = helperDoubleEmphasis(p, out, origData[offset-1:], c)
+ if length == 0 {
+ return 0
+ } else {
+ return length - 1
+ }
+ }
+ }
+ return 0
+}
diff --git a/vendor/src/github.com/russross/blackfriday/inline_test.go b/vendor/src/github.com/russross/blackfriday/inline_test.go
new file mode 100644
index 0000000..4e67d5c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/inline_test.go
@@ -0,0 +1,958 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Unit tests for inline parsing
+//
+
+package blackfriday
+
+import (
+ "regexp"
+ "testing"
+
+ "strings"
+)
+
+func runMarkdownInline(input string, extensions, htmlFlags int, params HtmlRendererParameters) string {
+ extensions |= EXTENSION_AUTOLINK
+ extensions |= EXTENSION_STRIKETHROUGH
+
+ htmlFlags |= HTML_USE_XHTML
+
+ renderer := HtmlRendererWithParameters(htmlFlags, "", "", params)
+
+ return string(Markdown([]byte(input), renderer, extensions))
+}
+
+func doTestsInline(t *testing.T, tests []string) {
+ doTestsInlineParam(t, tests, 0, 0, HtmlRendererParameters{})
+}
+
+func doLinkTestsInline(t *testing.T, tests []string) {
+ doTestsInline(t, tests)
+
+ prefix := "http://localhost"
+ params := HtmlRendererParameters{AbsolutePrefix: prefix}
+ transformTests := transformLinks(tests, prefix)
+ doTestsInlineParam(t, transformTests, 0, 0, params)
+ doTestsInlineParam(t, transformTests, 0, commonHtmlFlags, params)
+}
+
+func doSafeTestsInline(t *testing.T, tests []string) {
+ doTestsInlineParam(t, tests, 0, HTML_SAFELINK, HtmlRendererParameters{})
+
+ // All the links in this test should not have the prefix appended, so
+ // just rerun it with different parameters and the same expectations.
+ prefix := "http://localhost"
+ params := HtmlRendererParameters{AbsolutePrefix: prefix}
+ transformTests := transformLinks(tests, prefix)
+ doTestsInlineParam(t, transformTests, 0, HTML_SAFELINK, params)
+}
+
+func doTestsInlineParam(t *testing.T, tests []string, extensions, htmlFlags int,
+ params HtmlRendererParameters) {
+ // catch and report panics
+ var candidate string
+ /*
+ defer func() {
+ if err := recover(); err != nil {
+ t.Errorf("\npanic while processing [%#v] (%v)\n", candidate, err)
+ }
+ }()
+ */
+
+ for i := 0; i+1 < len(tests); i += 2 {
+ input := tests[i]
+ candidate = input
+ expected := tests[i+1]
+
+ actual := runMarkdownInline(candidate, extensions, htmlFlags, params)
+ if actual != expected {
+ t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
+ candidate, expected, actual)
+ }
+
+ // now test every substring to stress test bounds checking
+ if !testing.Short() {
+ for start := 0; start < len(input); start++ {
+ for end := start + 1; end <= len(input); end++ {
+ candidate = input[start:end]
+ _ = runMarkdownInline(candidate, extensions, htmlFlags, params)
+ }
+ }
+ }
+ }
+}
+
+func transformLinks(tests []string, prefix string) []string {
+ newTests := make([]string, len(tests))
+ anchorRe := regexp.MustCompile(`<a href="/(.*?)"`)
+ imgRe := regexp.MustCompile(`<img src="/(.*?)"`)
+ for i, test := range tests {
+ if i%2 == 1 {
+ test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`)
+ test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`)
+ }
+ newTests[i] = test
+ }
+ return newTests
+}
+
+func TestEmphasis(t *testing.T) {
+ var tests = []string{
+ "nothing inline\n",
+ "<p>nothing inline</p>\n",
+
+ "simple *inline* test\n",
+ "<p>simple <em>inline</em> test</p>\n",
+
+ "*at the* beginning\n",
+ "<p><em>at the</em> beginning</p>\n",
+
+ "at the *end*\n",
+ "<p>at the <em>end</em></p>\n",
+
+ "*try two* in *one line*\n",
+ "<p><em>try two</em> in <em>one line</em></p>\n",
+
+ "over *two\nlines* test\n",
+ "<p>over <em>two\nlines</em> test</p>\n",
+
+ "odd *number of* markers* here\n",
+ "<p>odd <em>number of</em> markers* here</p>\n",
+
+ "odd *number\nof* markers* here\n",
+ "<p>odd <em>number\nof</em> markers* here</p>\n",
+
+ "simple _inline_ test\n",
+ "<p>simple <em>inline</em> test</p>\n",
+
+ "_at the_ beginning\n",
+ "<p><em>at the</em> beginning</p>\n",
+
+ "at the _end_\n",
+ "<p>at the <em>end</em></p>\n",
+
+ "_try two_ in _one line_\n",
+ "<p><em>try two</em> in <em>one line</em></p>\n",
+
+ "over _two\nlines_ test\n",
+ "<p>over <em>two\nlines</em> test</p>\n",
+
+ "odd _number of_ markers_ here\n",
+ "<p>odd <em>number of</em> markers_ here</p>\n",
+
+ "odd _number\nof_ markers_ here\n",
+ "<p>odd <em>number\nof</em> markers_ here</p>\n",
+
+ "mix of *markers_\n",
+ "<p>mix of *markers_</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestStrong(t *testing.T) {
+ var tests = []string{
+ "nothing inline\n",
+ "<p>nothing inline</p>\n",
+
+ "simple **inline** test\n",
+ "<p>simple <strong>inline</strong> test</p>\n",
+
+ "**at the** beginning\n",
+ "<p><strong>at the</strong> beginning</p>\n",
+
+ "at the **end**\n",
+ "<p>at the <strong>end</strong></p>\n",
+
+ "**try two** in **one line**\n",
+ "<p><strong>try two</strong> in <strong>one line</strong></p>\n",
+
+ "over **two\nlines** test\n",
+ "<p>over <strong>two\nlines</strong> test</p>\n",
+
+ "odd **number of** markers** here\n",
+ "<p>odd <strong>number of</strong> markers** here</p>\n",
+
+ "odd **number\nof** markers** here\n",
+ "<p>odd <strong>number\nof</strong> markers** here</p>\n",
+
+ "simple __inline__ test\n",
+ "<p>simple <strong>inline</strong> test</p>\n",
+
+ "__at the__ beginning\n",
+ "<p><strong>at the</strong> beginning</p>\n",
+
+ "at the __end__\n",
+ "<p>at the <strong>end</strong></p>\n",
+
+ "__try two__ in __one line__\n",
+ "<p><strong>try two</strong> in <strong>one line</strong></p>\n",
+
+ "over __two\nlines__ test\n",
+ "<p>over <strong>two\nlines</strong> test</p>\n",
+
+ "odd __number of__ markers__ here\n",
+ "<p>odd <strong>number of</strong> markers__ here</p>\n",
+
+ "odd __number\nof__ markers__ here\n",
+ "<p>odd <strong>number\nof</strong> markers__ here</p>\n",
+
+ "mix of **markers__\n",
+ "<p>mix of **markers__</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestEmphasisMix(t *testing.T) {
+ var tests = []string{
+ "***triple emphasis***\n",
+ "<p><strong><em>triple emphasis</em></strong></p>\n",
+
+ "***triple\nemphasis***\n",
+ "<p><strong><em>triple\nemphasis</em></strong></p>\n",
+
+ "___triple emphasis___\n",
+ "<p><strong><em>triple emphasis</em></strong></p>\n",
+
+ "***triple emphasis___\n",
+ "<p>***triple emphasis___</p>\n",
+
+ "*__triple emphasis__*\n",
+ "<p><em><strong>triple emphasis</strong></em></p>\n",
+
+ "__*triple emphasis*__\n",
+ "<p><strong><em>triple emphasis</em></strong></p>\n",
+
+ "**improper *nesting** is* bad\n",
+ "<p><strong>improper *nesting</strong> is* bad</p>\n",
+
+ "*improper **nesting* is** bad\n",
+ "<p><em>improper **nesting</em> is** bad</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestEmphasisLink(t *testing.T) {
+ var tests = []string{
+ "[first](before) *text[second] (inside)text* [third](after)\n",
+ "<p><a href=\"before\">first</a> <em>text<a href=\"inside\">second</a>text</em> <a href=\"after\">third</a></p>\n",
+
+ "*incomplete [link] definition*\n",
+ "<p><em>incomplete [link] definition</em></p>\n",
+
+ "*it's [emphasis*] (not link)\n",
+ "<p><em>it's [emphasis</em>] (not link)</p>\n",
+
+ "*it's [emphasis*] and *[asterisk]\n",
+ "<p><em>it's [emphasis</em>] and *[asterisk]</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestStrikeThrough(t *testing.T) {
+ var tests = []string{
+ "nothing inline\n",
+ "<p>nothing inline</p>\n",
+
+ "simple ~~inline~~ test\n",
+ "<p>simple <del>inline</del> test</p>\n",
+
+ "~~at the~~ beginning\n",
+ "<p><del>at the</del> beginning</p>\n",
+
+ "at the ~~end~~\n",
+ "<p>at the <del>end</del></p>\n",
+
+ "~~try two~~ in ~~one line~~\n",
+ "<p><del>try two</del> in <del>one line</del></p>\n",
+
+ "over ~~two\nlines~~ test\n",
+ "<p>over <del>two\nlines</del> test</p>\n",
+
+ "odd ~~number of~~ markers~~ here\n",
+ "<p>odd <del>number of</del> markers~~ here</p>\n",
+
+ "odd ~~number\nof~~ markers~~ here\n",
+ "<p>odd <del>number\nof</del> markers~~ here</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestCodeSpan(t *testing.T) {
+ var tests = []string{
+ "`source code`\n",
+ "<p><code>source code</code></p>\n",
+
+ "` source code with spaces `\n",
+ "<p><code>source code with spaces</code></p>\n",
+
+ "` source code with spaces `not here\n",
+ "<p><code>source code with spaces</code>not here</p>\n",
+
+ "a `single marker\n",
+ "<p>a `single marker</p>\n",
+
+ "a single multi-tick marker with ``` no text\n",
+ "<p>a single multi-tick marker with ``` no text</p>\n",
+
+ "markers with ` ` a space\n",
+ "<p>markers with a space</p>\n",
+
+ "`source code` and a `stray\n",
+ "<p><code>source code</code> and a `stray</p>\n",
+
+ "`source *with* _awkward characters_ in it`\n",
+ "<p><code>source *with* _awkward characters_ in it</code></p>\n",
+
+ "`split over\ntwo lines`\n",
+ "<p><code>split over\ntwo lines</code></p>\n",
+
+ "```multiple ticks``` for the marker\n",
+ "<p><code>multiple ticks</code> for the marker</p>\n",
+
+ "```multiple ticks `with` ticks inside```\n",
+ "<p><code>multiple ticks `with` ticks inside</code></p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestLineBreak(t *testing.T) {
+ var tests = []string{
+ "this line \nhas a break\n",
+ "<p>this line<br />\nhas a break</p>\n",
+
+ "this line \ndoes not\n",
+ "<p>this line\ndoes not</p>\n",
+
+ "this line\\\ndoes not\n",
+ "<p>this line\\\ndoes not</p>\n",
+
+ "this line\\ \ndoes not\n",
+ "<p>this line\\\ndoes not</p>\n",
+
+ "this has an \nextra space\n",
+ "<p>this has an<br />\nextra space</p>\n",
+ }
+ doTestsInline(t, tests)
+
+ tests = []string{
+ "this line \nhas a break\n",
+ "<p>this line<br />\nhas a break</p>\n",
+
+ "this line \ndoes not\n",
+ "<p>this line\ndoes not</p>\n",
+
+ "this line\\\nhas a break\n",
+ "<p>this line<br />\nhas a break</p>\n",
+
+ "this line\\ \ndoes not\n",
+ "<p>this line\\\ndoes not</p>\n",
+
+ "this has an \nextra space\n",
+ "<p>this has an<br />\nextra space</p>\n",
+ }
+ doTestsInlineParam(t, tests, EXTENSION_BACKSLASH_LINE_BREAK, 0, HtmlRendererParameters{})
+}
+
+func TestInlineLink(t *testing.T) {
+ var tests = []string{
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+
+ "[foo with a title](/bar/ \"title\")\n",
+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
+
+ "[foo with a title](/bar/\t\"title\")\n",
+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
+
+ "[foo with a title](/bar/ \"title\" )\n",
+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
+
+ "[foo with a title](/bar/ title with no quotes)\n",
+ "<p><a href=\"/bar/ title with no quotes\">foo with a title</a></p>\n",
+
+ "[foo]()\n",
+ "<p>[foo]()</p>\n",
+
+ "![foo](/bar/)\n",
+ "<p><img src=\"/bar/\" alt=\"foo\" />\n</p>\n",
+
+ "![foo with a title](/bar/ \"title\")\n",
+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
+
+ "![foo with a title](/bar/\t\"title\")\n",
+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
+
+ "![foo with a title](/bar/ \"title\" )\n",
+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
+
+ "![foo with a title](/bar/ title with no quotes)\n",
+ "<p><img src=\"/bar/ title with no quotes\" alt=\"foo with a title\" />\n</p>\n",
+
+ "![](img.jpg)\n",
+ "<p><img src=\"img.jpg\" alt=\"\" />\n</p>\n",
+
+ "[link](url)\n",
+ "<p><a href=\"url\">link</a></p>\n",
+
+ "![foo]()\n",
+ "<p>![foo]()</p>\n",
+
+ "[a link]\t(/with_a_tab/)\n",
+ "<p><a href=\"/with_a_tab/\">a link</a></p>\n",
+
+ "[a link] (/with_spaces/)\n",
+ "<p><a href=\"/with_spaces/\">a link</a></p>\n",
+
+ "[text (with) [[nested] (brackets)]](/url/)\n",
+ "<p><a href=\"/url/\">text (with) [[nested] (brackets)]</a></p>\n",
+
+ "[text (with) [broken nested] (brackets)]](/url/)\n",
+ "<p>[text (with) <a href=\"brackets\">broken nested</a>]](/url/)</p>\n",
+
+ "[text\nwith a newline](/link/)\n",
+ "<p><a href=\"/link/\">text\nwith a newline</a></p>\n",
+
+ "[text in brackets] [followed](/by a link/)\n",
+ "<p>[text in brackets] <a href=\"/by a link/\">followed</a></p>\n",
+
+ "[link with\\] a closing bracket](/url/)\n",
+ "<p><a href=\"/url/\">link with] a closing bracket</a></p>\n",
+
+ "[link with\\[ an opening bracket](/url/)\n",
+ "<p><a href=\"/url/\">link with[ an opening bracket</a></p>\n",
+
+ "[link with\\) a closing paren](/url/)\n",
+ "<p><a href=\"/url/\">link with) a closing paren</a></p>\n",
+
+ "[link with\\( an opening paren](/url/)\n",
+ "<p><a href=\"/url/\">link with( an opening paren</a></p>\n",
+
+ "[link]( with whitespace)\n",
+ "<p><a href=\"with whitespace\">link</a></p>\n",
+
+ "[link]( with whitespace )\n",
+ "<p><a href=\"with whitespace\">link</a></p>\n",
+
+ "[![image](someimage)](with image)\n",
+ "<p><a href=\"with image\"><img src=\"someimage\" alt=\"image\" />\n</a></p>\n",
+
+ "[link](url \"one quote)\n",
+ "<p><a href=\"url "one quote\">link</a></p>\n",
+
+ "[link](url 'one quote)\n",
+ "<p><a href=\"url 'one quote\">link</a></p>\n",
+
+ "[link](<url>)\n",
+ "<p><a href=\"url\">link</a></p>\n",
+
+ "[link & ampersand](/url/)\n",
+ "<p><a href=\"/url/\">link & ampersand</a></p>\n",
+
+ "[link & ampersand](/url/)\n",
+ "<p><a href=\"/url/\">link & ampersand</a></p>\n",
+
+ "[link](/url/&query)\n",
+ "<p><a href=\"/url/&query\">link</a></p>\n",
+
+ "[[t]](/t)\n",
+ "<p><a href=\"/t\">[t]</a></p>\n",
+
+ "[link](</>)\n",
+ "<p><a href=\"/\">link</a></p>\n",
+
+ "[link](<./>)\n",
+ "<p><a href=\"./\">link</a></p>\n",
+
+ "[link](<../>)\n",
+ "<p><a href=\"../\">link</a></p>\n",
+ }
+ doLinkTestsInline(t, tests)
+
+}
+
+func TestRelAttrLink(t *testing.T) {
+ var nofollowTests = []string{
+ "[foo](http://bar.com/foo/)\n",
+ "<p><a href=\"http://bar.com/foo/\" rel=\"nofollow\">foo</a></p>\n",
+
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+
+ "[foo](/)\n",
+ "<p><a href=\"/\">foo</a></p>\n",
+
+ "[foo](./)\n",
+ "<p><a href=\"./\">foo</a></p>\n",
+
+ "[foo](../)\n",
+ "<p><a href=\"../\">foo</a></p>\n",
+
+ "[foo](../bar)\n",
+ "<p><a href=\"../bar\">foo</a></p>\n",
+ }
+ doTestsInlineParam(t, nofollowTests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS,
+ HtmlRendererParameters{})
+
+ var noreferrerTests = []string{
+ "[foo](http://bar.com/foo/)\n",
+ "<p><a href=\"http://bar.com/foo/\" rel=\"noreferrer\">foo</a></p>\n",
+
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+ }
+ doTestsInlineParam(t, noreferrerTests, 0, HTML_SAFELINK|HTML_NOREFERRER_LINKS,
+ HtmlRendererParameters{})
+
+ var nofollownoreferrerTests = []string{
+ "[foo](http://bar.com/foo/)\n",
+ "<p><a href=\"http://bar.com/foo/\" rel=\"nofollow noreferrer\">foo</a></p>\n",
+
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+ }
+ doTestsInlineParam(t, nofollownoreferrerTests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS|HTML_NOREFERRER_LINKS,
+ HtmlRendererParameters{})
+}
+
+func TestHrefTargetBlank(t *testing.T) {
+ var tests = []string{
+ // internal link
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+
+ "[foo](/)\n",
+ "<p><a href=\"/\">foo</a></p>\n",
+
+ "[foo](./)\n",
+ "<p><a href=\"./\">foo</a></p>\n",
+
+ "[foo](./bar)\n",
+ "<p><a href=\"./bar\">foo</a></p>\n",
+
+ "[foo](../)\n",
+ "<p><a href=\"../\">foo</a></p>\n",
+
+ "[foo](../bar)\n",
+ "<p><a href=\"../bar\">foo</a></p>\n",
+
+ "[foo](http://example.com)\n",
+ "<p><a href=\"http://example.com\" target=\"_blank\">foo</a></p>\n",
+ }
+ doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_HREF_TARGET_BLANK, HtmlRendererParameters{})
+}
+
+func TestSafeInlineLink(t *testing.T) {
+ var tests = []string{
+ "[foo](/bar/)\n",
+ "<p><a href=\"/bar/\">foo</a></p>\n",
+
+ "[foo](/)\n",
+ "<p><a href=\"/\">foo</a></p>\n",
+
+ "[foo](./)\n",
+ "<p><a href=\"./\">foo</a></p>\n",
+
+ "[foo](../)\n",
+ "<p><a href=\"../\">foo</a></p>\n",
+
+ "[foo](http://bar/)\n",
+ "<p><a href=\"http://bar/\">foo</a></p>\n",
+
+ "[foo](https://bar/)\n",
+ "<p><a href=\"https://bar/\">foo</a></p>\n",
+
+ "[foo](ftp://bar/)\n",
+ "<p><a href=\"ftp://bar/\">foo</a></p>\n",
+
+ "[foo](mailto://bar/)\n",
+ "<p><a href=\"mailto://bar/\">foo</a></p>\n",
+
+ // Not considered safe
+ "[foo](baz://bar/)\n",
+ "<p><tt>foo</tt></p>\n",
+ }
+ doSafeTestsInline(t, tests)
+}
+
+func TestReferenceLink(t *testing.T) {
+ var tests = []string{
+ "[link][ref]\n",
+ "<p>[link][ref]</p>\n",
+
+ "[link][ref]\n [ref]: /url/ \"title\"\n",
+ "<p><a href=\"/url/\" title=\"title\">link</a></p>\n",
+
+ "[link][ref]\n [ref]: /url/\n",
+ "<p><a href=\"/url/\">link</a></p>\n",
+
+ " [ref]: /url/\n",
+ "",
+
+ " [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n",
+ "",
+
+ " [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n [4spaces]: /url/\n",
+ "<pre><code>[4spaces]: /url/\n</code></pre>\n",
+
+ "[hmm](ref2)\n [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n",
+ "<p><a href=\"ref2\">hmm</a></p>\n",
+
+ "[ref]\n",
+ "<p>[ref]</p>\n",
+
+ "[ref]\n [ref]: /url/ \"title\"\n",
+ "<p><a href=\"/url/\" title=\"title\">ref</a></p>\n",
+
+ "[ref]\n [ref]: ../url/ \"title\"\n",
+ "<p><a href=\"../url/\" title=\"title\">ref</a></p>\n",
+ }
+ doLinkTestsInline(t, tests)
+}
+
+func TestTags(t *testing.T) {
+ var tests = []string{
+ "a <span>tag</span>\n",
+ "<p>a <span>tag</span></p>\n",
+
+ "<span>tag</span>\n",
+ "<p><span>tag</span></p>\n",
+
+ "<span>mismatch</spandex>\n",
+ "<p><span>mismatch</spandex></p>\n",
+
+ "a <singleton /> tag\n",
+ "<p>a <singleton /> tag</p>\n",
+ }
+ doTestsInline(t, tests)
+}
+
+func TestAutoLink(t *testing.T) {
+ var tests = []string{
+ "http://foo.com/\n",
+ "<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "1 http://foo.com/\n",
+ "<p>1 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "1http://foo.com/\n",
+ "<p>1<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "1.http://foo.com/\n",
+ "<p>1.<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "1. http://foo.com/\n",
+ "<ol>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ol>\n",
+
+ "-http://foo.com/\n",
+ "<p>-<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "- http://foo.com/\n",
+ "<ul>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ul>\n",
+
+ "_http://foo.com/\n",
+ "<p>_<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "令狐http://foo.com/\n",
+ "<p>令狐<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "令狐 http://foo.com/\n",
+ "<p>令狐 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "ahttp://foo.com/\n",
+ "<p>ahttp://foo.com/</p>\n",
+
+ ">http://foo.com/\n",
+ "<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n",
+
+ "> http://foo.com/\n",
+ "<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n",
+
+ "go to <http://foo.com/>\n",
+ "<p>go to <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
+
+ "a secure <https://link.org>\n",
+ "<p>a secure <a href=\"https://link.org\">https://link.org</a></p>\n",
+
+ "an email <mailto:some@one.com>\n",
+ "<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n",
+
+ "an email <mailto://some@one.com>\n",
+ "<p>an email <a href=\"mailto://some@one.com\">some@one.com</a></p>\n",
+
+ "an email <some@one.com>\n",
+ "<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n",
+
+ "an ftp <ftp://old.com>\n",
+ "<p>an ftp <a href=\"ftp://old.com\">ftp://old.com</a></p>\n",
+
+ "an ftp <ftp:old.com>\n",
+ "<p>an ftp <a href=\"ftp:old.com\">ftp:old.com</a></p>\n",
+
+ "a link with <http://new.com?query=foo&bar>\n",
+ "<p>a link with <a href=\"http://new.com?query=foo&bar\">" +
+ "http://new.com?query=foo&bar</a></p>\n",
+
+ "quotes mean a tag <http://new.com?query=\"foo\"&bar>\n",
+ "<p>quotes mean a tag <http://new.com?query=\"foo\"&bar></p>\n",
+
+ "quotes mean a tag <http://new.com?query='foo'&bar>\n",
+ "<p>quotes mean a tag <http://new.com?query='foo'&bar></p>\n",
+
+ "unless escaped <http://new.com?query=\\\"foo\\\"&bar>\n",
+ "<p>unless escaped <a href=\"http://new.com?query="foo"&bar\">" +
+ "http://new.com?query="foo"&bar</a></p>\n",
+
+ "even a > can be escaped <http://new.com?q=\\>&etc>\n",
+ "<p>even a > can be escaped <a href=\"http://new.com?q=>&etc\">" +
+ "http://new.com?q=>&etc</a></p>\n",
+
+ "<a href=\"http://fancy.com\">http://fancy.com</a>\n",
+ "<p><a href=\"http://fancy.com\">http://fancy.com</a></p>\n",
+
+ "<a href=\"http://fancy.com\">This is a link</a>\n",
+ "<p><a href=\"http://fancy.com\">This is a link</a></p>\n",
+
+ "<a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a>\n",
+ "<p><a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a></p>\n",
+
+ "(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (\n",
+ "<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (</p>\n",
+
+ "(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).\n",
+ "<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).</p>\n",
+
+ "http://www.foo.com<br />\n",
+ "<p><a href=\"http://www.foo.com\">http://www.foo.com</a><br /></p>\n",
+
+ "http://foo.com/viewtopic.php?f=18&t=297",
+ "<p><a href=\"http://foo.com/viewtopic.php?f=18&t=297\">http://foo.com/viewtopic.php?f=18&t=297</a></p>\n",
+
+ "http://foo.com/viewtopic.php?param="18"zz",
+ "<p><a href=\"http://foo.com/viewtopic.php?param="18"zz\">http://foo.com/viewtopic.php?param="18"zz</a></p>\n",
+
+ "http://foo.com/viewtopic.php?param="18"",
+ "<p><a href=\"http://foo.com/viewtopic.php?param="18"\">http://foo.com/viewtopic.php?param="18"</a></p>\n",
+ }
+ doLinkTestsInline(t, tests)
+}
+
+var footnoteTests = []string{
+ "testing footnotes.[^a]\n\n[^a]: This is the note\n",
+ `<p>testing footnotes.<sup class="footnote-ref" id="fnref:a"><a rel="footnote" href="#fn:a">1</a></sup></p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:a">This is the note
+</li>
+</ol>
+</div>
+`,
+
+ `testing long[^b] notes.
+
+[^b]: Paragraph 1
+
+ Paragraph 2
+
+ ` + "```\n\tsome code\n\t```" + `
+
+ Paragraph 3
+
+No longer in the footnote
+`,
+ `<p>testing long<sup class="footnote-ref" id="fnref:b"><a rel="footnote" href="#fn:b">1</a></sup> notes.</p>
+
+<p>No longer in the footnote</p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:b"><p>Paragraph 1</p>
+
+<p>Paragraph 2</p>
+
+<p><code>
+some code
+</code></p>
+
+<p>Paragraph 3</p>
+</li>
+</ol>
+</div>
+`,
+
+ `testing[^c] multiple[^d] notes.
+
+[^c]: this is [note] c
+
+
+omg
+
+[^d]: this is note d
+
+what happens here
+
+[note]: /link/c
+
+`,
+ `<p>testing<sup class="footnote-ref" id="fnref:c"><a rel="footnote" href="#fn:c">1</a></sup> multiple<sup class="footnote-ref" id="fnref:d"><a rel="footnote" href="#fn:d">2</a></sup> notes.</p>
+
+<p>omg</p>
+
+<p>what happens here</p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:c">this is <a href="/link/c">note</a> c
+</li>
+<li id="fn:d">this is note d
+</li>
+</ol>
+</div>
+`,
+
+ "testing inline^[this is the note] notes.\n",
+ `<p>testing inline<sup class="footnote-ref" id="fnref:this-is-the-note"><a rel="footnote" href="#fn:this-is-the-note">1</a></sup> notes.</p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:this-is-the-note">this is the note</li>
+</ol>
+</div>
+`,
+
+ "testing multiple[^1] types^[inline note] of notes[^2]\n\n[^2]: the second deferred note\n[^1]: the first deferred note\n\n\twhich happens to be a block\n",
+ `<p>testing multiple<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup> types<sup class="footnote-ref" id="fnref:inline-note"><a rel="footnote" href="#fn:inline-note">2</a></sup> of notes<sup class="footnote-ref" id="fnref:2"><a rel="footnote" href="#fn:2">3</a></sup></p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:1"><p>the first deferred note</p>
+
+<p>which happens to be a block</p>
+</li>
+<li id="fn:inline-note">inline note</li>
+<li id="fn:2">the second deferred note
+</li>
+</ol>
+</div>
+`,
+
+ `This is a footnote[^1]^[and this is an inline footnote]
+
+[^1]: the footnote text.
+
+ may be multiple paragraphs.
+`,
+ `<p>This is a footnote<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup><sup class="footnote-ref" id="fnref:and-this-is-an-i"><a rel="footnote" href="#fn:and-this-is-an-i">2</a></sup></p>
+<div class="footnotes">
+
+<hr />
+
+<ol>
+<li id="fn:1"><p>the footnote text.</p>
+
+<p>may be multiple paragraphs.</p>
+</li>
+<li id="fn:and-this-is-an-i">and this is an inline footnote</li>
+</ol>
+</div>
+`,
+
+ "empty footnote[^]\n\n[^]: fn text",
+ "<p>empty footnote<sup class=\"footnote-ref\" id=\"fnref:\"><a rel=\"footnote\" href=\"#fn:\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:\">fn text\n</li>\n</ol>\n</div>\n",
+
+ "Some text.[^note1]\n\n[^note1]: fn1",
+ "<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n</ol>\n</div>\n",
+
+ "Some text.[^note1][^note2]\n\n[^note1]: fn1\n[^note2]: fn2\n",
+ "<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup><sup class=\"footnote-ref\" id=\"fnref:note2\"><a rel=\"footnote\" href=\"#fn:note2\">2</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n<li id=\"fn:note2\">fn2\n</li>\n</ol>\n</div>\n",
+}
+
+func TestFootnotes(t *testing.T) {
+ doTestsInlineParam(t, footnoteTests, EXTENSION_FOOTNOTES, 0, HtmlRendererParameters{})
+}
+
+func TestFootnotesWithParameters(t *testing.T) {
+ tests := make([]string, len(footnoteTests))
+
+ prefix := "testPrefix"
+ returnText := "ret"
+ re := regexp.MustCompile(`(?ms)<li id="fn:(\S+?)">(.*?)</li>`)
+
+ // Transform the test expectations to match the parameters we're using.
+ for i, test := range footnoteTests {
+ if i%2 == 1 {
+ test = strings.Replace(test, "fn:", "fn:"+prefix, -1)
+ test = strings.Replace(test, "fnref:", "fnref:"+prefix, -1)
+ test = re.ReplaceAllString(test, `<li id="fn:$1">$2 <a class="footnote-return" href="#fnref:$1">ret</a></li>`)
+ }
+ tests[i] = test
+ }
+
+ params := HtmlRendererParameters{
+ FootnoteAnchorPrefix: prefix,
+ FootnoteReturnLinkContents: returnText,
+ }
+
+ doTestsInlineParam(t, tests, EXTENSION_FOOTNOTES, HTML_FOOTNOTE_RETURN_LINKS, params)
+}
+
+func TestSmartDoubleQuotes(t *testing.T) {
+ var tests = []string{
+ "this should be normal \"quoted\" text.\n",
+ "<p>this should be normal “quoted” text.</p>\n",
+ "this \" single double\n",
+ "<p>this “ single double</p>\n",
+ "two pair of \"some\" quoted \"text\".\n",
+ "<p>two pair of “some” quoted “text”.</p>\n"}
+
+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS, HtmlRendererParameters{})
+}
+
+func TestSmartAngledDoubleQuotes(t *testing.T) {
+ var tests = []string{
+ "this should be angled \"quoted\" text.\n",
+ "<p>this should be angled «quoted» text.</p>\n",
+ "this \" single double\n",
+ "<p>this « single double</p>\n",
+ "two pair of \"some\" quoted \"text\".\n",
+ "<p>two pair of «some» quoted «text».</p>\n"}
+
+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_ANGLED_QUOTES, HtmlRendererParameters{})
+}
+
+func TestSmartFractions(t *testing.T) {
+ var tests = []string{
+ "1/2, 1/4 and 3/4; 1/4th and 3/4ths\n",
+ "<p>½, ¼ and ¾; ¼th and ¾ths</p>\n",
+ "1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n",
+ "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"}
+
+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS, HtmlRendererParameters{})
+
+ tests = []string{
+ "1/2, 2/3, 81/100 and 1000000/1048576.\n",
+ "<p><sup>1</sup>⁄<sub>2</sub>, <sup>2</sup>⁄<sub>3</sub>, <sup>81</sup>⁄<sub>100</sub> and <sup>1000000</sup>⁄<sub>1048576</sub>.</p>\n",
+ "1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n",
+ "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"}
+
+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_FRACTIONS, HtmlRendererParameters{})
+}
diff --git a/vendor/src/github.com/russross/blackfriday/latex.go b/vendor/src/github.com/russross/blackfriday/latex.go
new file mode 100644
index 0000000..8562746
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/latex.go
@@ -0,0 +1,332 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+//
+// LaTeX rendering backend
+//
+//
+
+package blackfriday
+
+import (
+ "bytes"
+)
+
+// Latex is a type that implements the Renderer interface for LaTeX output.
+//
+// Do not create this directly, instead use the LatexRenderer function.
+type Latex struct {
+}
+
+// LatexRenderer creates and configures a Latex object, which
+// satisfies the Renderer interface.
+//
+// flags is a set of LATEX_* options ORed together (currently no such options
+// are defined).
+func LatexRenderer(flags int) Renderer {
+ return &Latex{}
+}
+
+func (options *Latex) GetFlags() int {
+ return 0
+}
+
+// render code chunks using verbatim, or listings if we have a language
+func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) {
+ if lang == "" {
+ out.WriteString("\n\\begin{verbatim}\n")
+ } else {
+ out.WriteString("\n\\begin{lstlisting}[language=")
+ out.WriteString(lang)
+ out.WriteString("]\n")
+ }
+ out.Write(text)
+ if lang == "" {
+ out.WriteString("\n\\end{verbatim}\n")
+ } else {
+ out.WriteString("\n\\end{lstlisting}\n")
+ }
+}
+
+func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) {
+
+}
+
+func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) {
+ out.WriteString("\n\\begin{quotation}\n")
+ out.Write(text)
+ out.WriteString("\n\\end{quotation}\n")
+}
+
+func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) {
+ // a pretty lame thing to do...
+ out.WriteString("\n\\begin{verbatim}\n")
+ out.Write(text)
+ out.WriteString("\n\\end{verbatim}\n")
+}
+
+func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) {
+ marker := out.Len()
+
+ switch level {
+ case 1:
+ out.WriteString("\n\\section{")
+ case 2:
+ out.WriteString("\n\\subsection{")
+ case 3:
+ out.WriteString("\n\\subsubsection{")
+ case 4:
+ out.WriteString("\n\\paragraph{")
+ case 5:
+ out.WriteString("\n\\subparagraph{")
+ case 6:
+ out.WriteString("\n\\textbf{")
+ }
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ out.WriteString("}\n")
+}
+
+func (options *Latex) HRule(out *bytes.Buffer) {
+ out.WriteString("\n\\HRule\n")
+}
+
+func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) {
+ marker := out.Len()
+ if flags&LIST_TYPE_ORDERED != 0 {
+ out.WriteString("\n\\begin{enumerate}\n")
+ } else {
+ out.WriteString("\n\\begin{itemize}\n")
+ }
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ if flags&LIST_TYPE_ORDERED != 0 {
+ out.WriteString("\n\\end{enumerate}\n")
+ } else {
+ out.WriteString("\n\\end{itemize}\n")
+ }
+}
+
+func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) {
+ out.WriteString("\n\\item ")
+ out.Write(text)
+}
+
+func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) {
+ marker := out.Len()
+ out.WriteString("\n")
+ if !text() {
+ out.Truncate(marker)
+ return
+ }
+ out.WriteString("\n")
+}
+
+func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
+ out.WriteString("\n\\begin{tabular}{")
+ for _, elt := range columnData {
+ switch elt {
+ case TABLE_ALIGNMENT_LEFT:
+ out.WriteByte('l')
+ case TABLE_ALIGNMENT_RIGHT:
+ out.WriteByte('r')
+ default:
+ out.WriteByte('c')
+ }
+ }
+ out.WriteString("}\n")
+ out.Write(header)
+ out.WriteString(" \\\\\n\\hline\n")
+ out.Write(body)
+ out.WriteString("\n\\end{tabular}\n")
+}
+
+func (options *Latex) TableRow(out *bytes.Buffer, text []byte) {
+ if out.Len() > 0 {
+ out.WriteString(" \\\\\n")
+ }
+ out.Write(text)
+}
+
+func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) {
+ if out.Len() > 0 {
+ out.WriteString(" & ")
+ }
+ out.Write(text)
+}
+
+func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) {
+ if out.Len() > 0 {
+ out.WriteString(" & ")
+ }
+ out.Write(text)
+}
+
+// TODO: this
+func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) {
+
+}
+
+func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) {
+
+}
+
+func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) {
+ out.WriteString("\\href{")
+ if kind == LINK_TYPE_EMAIL {
+ out.WriteString("mailto:")
+ }
+ out.Write(link)
+ out.WriteString("}{")
+ out.Write(link)
+ out.WriteString("}")
+}
+
+func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\texttt{")
+ escapeSpecialChars(out, text)
+ out.WriteString("}")
+}
+
+func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\textbf{")
+ out.Write(text)
+ out.WriteString("}")
+}
+
+func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\textit{")
+ out.Write(text)
+ out.WriteString("}")
+}
+
+func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
+ if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) {
+ // treat it like a link
+ out.WriteString("\\href{")
+ out.Write(link)
+ out.WriteString("}{")
+ out.Write(alt)
+ out.WriteString("}")
+ } else {
+ out.WriteString("\\includegraphics{")
+ out.Write(link)
+ out.WriteString("}")
+ }
+}
+
+func (options *Latex) LineBreak(out *bytes.Buffer) {
+ out.WriteString(" \\\\\n")
+}
+
+func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
+ out.WriteString("\\href{")
+ out.Write(link)
+ out.WriteString("}{")
+ out.Write(content)
+ out.WriteString("}")
+}
+
+func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) {
+}
+
+func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\textbf{\\textit{")
+ out.Write(text)
+ out.WriteString("}}")
+}
+
+func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) {
+ out.WriteString("\\sout{")
+ out.Write(text)
+ out.WriteString("}")
+}
+
+// TODO: this
+func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) {
+
+}
+
+func needsBackslash(c byte) bool {
+ for _, r := range []byte("_{}%$&\\~") {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+func escapeSpecialChars(out *bytes.Buffer, text []byte) {
+ for i := 0; i < len(text); i++ {
+ // directly copy normal characters
+ org := i
+
+ for i < len(text) && !needsBackslash(text[i]) {
+ i++
+ }
+ if i > org {
+ out.Write(text[org:i])
+ }
+
+ // escape a character
+ if i >= len(text) {
+ break
+ }
+ out.WriteByte('\\')
+ out.WriteByte(text[i])
+ }
+}
+
+func (options *Latex) Entity(out *bytes.Buffer, entity []byte) {
+ // TODO: convert this into a unicode character or something
+ out.Write(entity)
+}
+
+func (options *Latex) NormalText(out *bytes.Buffer, text []byte) {
+ escapeSpecialChars(out, text)
+}
+
+// header and footer
+func (options *Latex) DocumentHeader(out *bytes.Buffer) {
+ out.WriteString("\\documentclass{article}\n")
+ out.WriteString("\n")
+ out.WriteString("\\usepackage{graphicx}\n")
+ out.WriteString("\\usepackage{listings}\n")
+ out.WriteString("\\usepackage[margin=1in]{geometry}\n")
+ out.WriteString("\\usepackage[utf8]{inputenc}\n")
+ out.WriteString("\\usepackage{verbatim}\n")
+ out.WriteString("\\usepackage[normalem]{ulem}\n")
+ out.WriteString("\\usepackage{hyperref}\n")
+ out.WriteString("\n")
+ out.WriteString("\\hypersetup{colorlinks,%\n")
+ out.WriteString(" citecolor=black,%\n")
+ out.WriteString(" filecolor=black,%\n")
+ out.WriteString(" linkcolor=black,%\n")
+ out.WriteString(" urlcolor=black,%\n")
+ out.WriteString(" pdfstartview=FitH,%\n")
+ out.WriteString(" breaklinks=true,%\n")
+ out.WriteString(" pdfauthor={Blackfriday Markdown Processor v")
+ out.WriteString(VERSION)
+ out.WriteString("}}\n")
+ out.WriteString("\n")
+ out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n")
+ out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n")
+ out.WriteString("\\parindent=0pt\n")
+ out.WriteString("\n")
+ out.WriteString("\\begin{document}\n")
+}
+
+func (options *Latex) DocumentFooter(out *bytes.Buffer) {
+ out.WriteString("\n\\end{document}\n")
+}
diff --git a/vendor/src/github.com/russross/blackfriday/markdown.go b/vendor/src/github.com/russross/blackfriday/markdown.go
new file mode 100644
index 0000000..e2cd95b
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/markdown.go
@@ -0,0 +1,838 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+//
+// Markdown parsing and processing
+//
+//
+
+// Blackfriday markdown processor.
+//
+// Translates plain text with simple formatting rules into HTML or LaTeX.
+package blackfriday
+
+import (
+ "bytes"
+ "unicode/utf8"
+)
+
+const VERSION = "1.1"
+
+// These are the supported markdown parsing extensions.
+// OR these values together to select multiple extensions.
+const (
+ EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words
+ EXTENSION_TABLES // render tables
+ EXTENSION_FENCED_CODE // render fenced code blocks
+ EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked
+ EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~
+ EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules
+ EXTENSION_SPACE_HEADERS // be strict about prefix header rules
+ EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks
+ EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four
+ EXTENSION_FOOTNOTES // Pandoc-style footnotes
+ EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, order list, unorder list)block
+ EXTENSION_HEADER_IDS // specify header IDs with {#id}
+ EXTENSION_TITLEBLOCK // Titleblock ala pandoc
+ EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text
+ EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks
+
+ commonHtmlFlags = 0 |
+ HTML_USE_XHTML |
+ HTML_USE_SMARTYPANTS |
+ HTML_SMARTYPANTS_FRACTIONS |
+ HTML_SMARTYPANTS_LATEX_DASHES
+
+ commonExtensions = 0 |
+ EXTENSION_NO_INTRA_EMPHASIS |
+ EXTENSION_TABLES |
+ EXTENSION_FENCED_CODE |
+ EXTENSION_AUTOLINK |
+ EXTENSION_STRIKETHROUGH |
+ EXTENSION_SPACE_HEADERS |
+ EXTENSION_HEADER_IDS |
+ EXTENSION_BACKSLASH_LINE_BREAK
+)
+
+// These are the possible flag values for the link renderer.
+// Only a single one of these values will be used; they are not ORed together.
+// These are mostly of interest if you are writing a new output format.
+const (
+ LINK_TYPE_NOT_AUTOLINK = iota
+ LINK_TYPE_NORMAL
+ LINK_TYPE_EMAIL
+)
+
+// These are the possible flag values for the ListItem renderer.
+// Multiple flag values may be ORed together.
+// These are mostly of interest if you are writing a new output format.
+const (
+ LIST_TYPE_ORDERED = 1 << iota
+ LIST_ITEM_CONTAINS_BLOCK
+ LIST_ITEM_BEGINNING_OF_LIST
+ LIST_ITEM_END_OF_LIST
+)
+
+// These are the possible flag values for the table cell renderer.
+// Only a single one of these values will be used; they are not ORed together.
+// These are mostly of interest if you are writing a new output format.
+const (
+ TABLE_ALIGNMENT_LEFT = 1 << iota
+ TABLE_ALIGNMENT_RIGHT
+ TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT)
+)
+
+// The size of a tab stop.
+const (
+ TAB_SIZE_DEFAULT = 4
+ TAB_SIZE_EIGHT = 8
+)
+
+// These are the tags that are recognized as HTML block tags.
+// Any of these can be included in markdown text without special escaping.
+var blockTags = map[string]bool{
+ "p": true,
+ "dl": true,
+ "h1": true,
+ "h2": true,
+ "h3": true,
+ "h4": true,
+ "h5": true,
+ "h6": true,
+ "ol": true,
+ "ul": true,
+ "del": true,
+ "div": true,
+ "ins": true,
+ "pre": true,
+ "form": true,
+ "math": true,
+ "table": true,
+ "iframe": true,
+ "script": true,
+ "fieldset": true,
+ "noscript": true,
+ "blockquote": true,
+
+ // HTML5
+ "video": true,
+ "aside": true,
+ "canvas": true,
+ "figure": true,
+ "footer": true,
+ "header": true,
+ "hgroup": true,
+ "output": true,
+ "article": true,
+ "section": true,
+ "progress": true,
+ "figcaption": true,
+}
+
+// Renderer is the rendering interface.
+// This is mostly of interest if you are implementing a new rendering format.
+//
+// When a byte slice is provided, it contains the (rendered) contents of the
+// element.
+//
+// When a callback is provided instead, it will write the contents of the
+// respective element directly to the output buffer and return true on success.
+// If the callback returns false, the rendering function should reset the
+// output buffer as though it had never been called.
+//
+// Currently Html and Latex implementations are provided
+type Renderer interface {
+ // block-level callbacks
+ BlockCode(out *bytes.Buffer, text []byte, lang string)
+ BlockQuote(out *bytes.Buffer, text []byte)
+ BlockHtml(out *bytes.Buffer, text []byte)
+ Header(out *bytes.Buffer, text func() bool, level int, id string)
+ HRule(out *bytes.Buffer)
+ List(out *bytes.Buffer, text func() bool, flags int)
+ ListItem(out *bytes.Buffer, text []byte, flags int)
+ Paragraph(out *bytes.Buffer, text func() bool)
+ Table(out *bytes.Buffer, header []byte, body []byte, columnData []int)
+ TableRow(out *bytes.Buffer, text []byte)
+ TableHeaderCell(out *bytes.Buffer, text []byte, flags int)
+ TableCell(out *bytes.Buffer, text []byte, flags int)
+ Footnotes(out *bytes.Buffer, text func() bool)
+ FootnoteItem(out *bytes.Buffer, name, text []byte, flags int)
+ TitleBlock(out *bytes.Buffer, text []byte)
+
+ // Span-level callbacks
+ AutoLink(out *bytes.Buffer, link []byte, kind int)
+ CodeSpan(out *bytes.Buffer, text []byte)
+ DoubleEmphasis(out *bytes.Buffer, text []byte)
+ Emphasis(out *bytes.Buffer, text []byte)
+ Image(out *bytes.Buffer, link []byte, title []byte, alt []byte)
+ LineBreak(out *bytes.Buffer)
+ Link(out *bytes.Buffer, link []byte, title []byte, content []byte)
+ RawHtmlTag(out *bytes.Buffer, tag []byte)
+ TripleEmphasis(out *bytes.Buffer, text []byte)
+ StrikeThrough(out *bytes.Buffer, text []byte)
+ FootnoteRef(out *bytes.Buffer, ref []byte, id int)
+
+ // Low-level callbacks
+ Entity(out *bytes.Buffer, entity []byte)
+ NormalText(out *bytes.Buffer, text []byte)
+
+ // Header and footer
+ DocumentHeader(out *bytes.Buffer)
+ DocumentFooter(out *bytes.Buffer)
+
+ GetFlags() int
+}
+
+// Callback functions for inline parsing. One such function is defined
+// for each character that triggers a response when parsing inline data.
+type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int
+
+// Parser holds runtime state used by the parser.
+// This is constructed by the Markdown function.
+type parser struct {
+ r Renderer
+ refs map[string]*reference
+ inlineCallback [256]inlineParser
+ flags int
+ nesting int
+ maxNesting int
+ insideLink bool
+
+ // Footnotes need to be ordered as well as available to quickly check for
+ // presence. If a ref is also a footnote, it's stored both in refs and here
+ // in notes. Slice is nil if footnotes not enabled.
+ notes []*reference
+}
+
+//
+//
+// Public interface
+//
+//
+
+// MarkdownBasic is a convenience function for simple rendering.
+// It processes markdown input with no extensions enabled.
+func MarkdownBasic(input []byte) []byte {
+ // set up the HTML renderer
+ htmlFlags := HTML_USE_XHTML
+ renderer := HtmlRenderer(htmlFlags, "", "")
+
+ // set up the parser
+ extensions := 0
+
+ return Markdown(input, renderer, extensions)
+}
+
+// Call Markdown with most useful extensions enabled
+// MarkdownCommon is a convenience function for simple rendering.
+// It processes markdown input with common extensions enabled, including:
+//
+// * Smartypants processing with smart fractions and LaTeX dashes
+//
+// * Intra-word emphasis suppression
+//
+// * Tables
+//
+// * Fenced code blocks
+//
+// * Autolinking
+//
+// * Strikethrough support
+//
+// * Strict header parsing
+//
+// * Custom Header IDs
+func MarkdownCommon(input []byte) []byte {
+ // set up the HTML renderer
+ renderer := HtmlRenderer(commonHtmlFlags, "", "")
+ return Markdown(input, renderer, commonExtensions)
+}
+
+// Markdown is the main rendering function.
+// It parses and renders a block of markdown-encoded text.
+// The supplied Renderer is used to format the output, and extensions dictates
+// which non-standard extensions are enabled.
+//
+// To use the supplied Html or LaTeX renderers, see HtmlRenderer and
+// LatexRenderer, respectively.
+func Markdown(input []byte, renderer Renderer, extensions int) []byte {
+ // no point in parsing if we can't render
+ if renderer == nil {
+ return nil
+ }
+
+ // fill in the render structure
+ p := new(parser)
+ p.r = renderer
+ p.flags = extensions
+ p.refs = make(map[string]*reference)
+ p.maxNesting = 16
+ p.insideLink = false
+
+ // register inline parsers
+ p.inlineCallback['*'] = emphasis
+ p.inlineCallback['_'] = emphasis
+ if extensions&EXTENSION_STRIKETHROUGH != 0 {
+ p.inlineCallback['~'] = emphasis
+ }
+ p.inlineCallback['`'] = codeSpan
+ p.inlineCallback['\n'] = lineBreak
+ p.inlineCallback['['] = link
+ p.inlineCallback['<'] = leftAngle
+ p.inlineCallback['\\'] = escape
+ p.inlineCallback['&'] = entity
+
+ if extensions&EXTENSION_AUTOLINK != 0 {
+ p.inlineCallback[':'] = autoLink
+ }
+
+ if extensions&EXTENSION_FOOTNOTES != 0 {
+ p.notes = make([]*reference, 0)
+ }
+
+ first := firstPass(p, input)
+ second := secondPass(p, first)
+ return second
+}
+
+// first pass:
+// - extract references
+// - expand tabs
+// - normalize newlines
+// - copy everything else
+// - add missing newlines before fenced code blocks
+func firstPass(p *parser, input []byte) []byte {
+ var out bytes.Buffer
+ tabSize := TAB_SIZE_DEFAULT
+ if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 {
+ tabSize = TAB_SIZE_EIGHT
+ }
+ beg, end := 0, 0
+ lastLineWasBlank := false
+ lastFencedCodeBlockEnd := 0
+ for beg < len(input) { // iterate over lines
+ if end = isReference(p, input[beg:], tabSize); end > 0 {
+ beg += end
+ } else { // skip to the next line
+ end = beg
+ for end < len(input) && input[end] != '\n' && input[end] != '\r' {
+ end++
+ }
+
+ if p.flags&EXTENSION_FENCED_CODE != 0 {
+ // when last line was none blank and a fenced code block comes after
+ if beg >= lastFencedCodeBlockEnd {
+ if i := p.fencedCode(&out, input[beg:], false); i > 0 {
+ if !lastLineWasBlank {
+ out.WriteByte('\n') // need to inject additional linebreak
+ }
+ lastFencedCodeBlockEnd = beg + i
+ }
+ }
+ lastLineWasBlank = end == beg
+ }
+
+ // add the line body if present
+ if end > beg {
+ if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks.
+ out.Write(input[beg:end])
+ } else {
+ expandTabs(&out, input[beg:end], tabSize)
+ }
+ }
+ out.WriteByte('\n')
+
+ if end < len(input) && input[end] == '\r' {
+ end++
+ }
+ if end < len(input) && input[end] == '\n' {
+ end++
+ }
+
+ beg = end
+ }
+ }
+
+ // empty input?
+ if out.Len() == 0 {
+ out.WriteByte('\n')
+ }
+
+ return out.Bytes()
+}
+
+// second pass: actual rendering
+func secondPass(p *parser, input []byte) []byte {
+ var output bytes.Buffer
+
+ p.r.DocumentHeader(&output)
+ p.block(&output, input)
+
+ if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 {
+ p.r.Footnotes(&output, func() bool {
+ flags := LIST_ITEM_BEGINNING_OF_LIST
+ for _, ref := range p.notes {
+ var buf bytes.Buffer
+ if ref.hasBlock {
+ flags |= LIST_ITEM_CONTAINS_BLOCK
+ p.block(&buf, ref.title)
+ } else {
+ p.inline(&buf, ref.title)
+ }
+ p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags)
+ flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK
+ }
+
+ return true
+ })
+ }
+
+ p.r.DocumentFooter(&output)
+
+ if p.nesting != 0 {
+ panic("Nesting level did not end at zero")
+ }
+
+ return output.Bytes()
+}
+
+//
+// Link references
+//
+// This section implements support for references that (usually) appear
+// as footnotes in a document, and can be referenced anywhere in the document.
+// The basic format is:
+//
+// [1]: http://www.google.com/ "Google"
+// [2]: http://www.github.com/ "Github"
+//
+// Anywhere in the document, the reference can be linked by referring to its
+// label, i.e., 1 and 2 in this example, as in:
+//
+// This library is hosted on [Github][2], a git hosting site.
+//
+// Actual footnotes as specified in Pandoc and supported by some other Markdown
+// libraries such as php-markdown are also taken care of. They look like this:
+//
+// This sentence needs a bit of further explanation.[^note]
+//
+// [^note]: This is the explanation.
+//
+// Footnotes should be placed at the end of the document in an ordered list.
+// Inline footnotes such as:
+//
+// Inline footnotes^[Not supported.] also exist.
+//
+// are not yet supported.
+
+// References are parsed and stored in this struct.
+type reference struct {
+ link []byte
+ title []byte
+ noteId int // 0 if not a footnote ref
+ hasBlock bool
+}
+
+// Check whether or not data starts with a reference link.
+// If so, it is parsed and stored in the list of references
+// (in the render struct).
+// Returns the number of bytes to skip to move past it,
+// or zero if the first line is not a reference.
+func isReference(p *parser, data []byte, tabSize int) int {
+ // up to 3 optional leading spaces
+ if len(data) < 4 {
+ return 0
+ }
+ i := 0
+ for i < 3 && data[i] == ' ' {
+ i++
+ }
+
+ noteId := 0
+
+ // id part: anything but a newline between brackets
+ if data[i] != '[' {
+ return 0
+ }
+ i++
+ if p.flags&EXTENSION_FOOTNOTES != 0 {
+ if data[i] == '^' {
+ // we can set it to anything here because the proper noteIds will
+ // be assigned later during the second pass. It just has to be != 0
+ noteId = 1
+ i++
+ }
+ }
+ idOffset := i
+ for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' {
+ i++
+ }
+ if i >= len(data) || data[i] != ']' {
+ return 0
+ }
+ idEnd := i
+
+ // spacer: colon (space | tab)* newline? (space | tab)*
+ i++
+ if i >= len(data) || data[i] != ':' {
+ return 0
+ }
+ i++
+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
+ i++
+ }
+ if i < len(data) && (data[i] == '\n' || data[i] == '\r') {
+ i++
+ if i < len(data) && data[i] == '\n' && data[i-1] == '\r' {
+ i++
+ }
+ }
+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
+ i++
+ }
+ if i >= len(data) {
+ return 0
+ }
+
+ var (
+ linkOffset, linkEnd int
+ titleOffset, titleEnd int
+ lineEnd int
+ raw []byte
+ hasBlock bool
+ )
+
+ if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 {
+ linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize)
+ lineEnd = linkEnd
+ } else {
+ linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i)
+ }
+ if lineEnd == 0 {
+ return 0
+ }
+
+ // a valid ref has been found
+
+ ref := &reference{
+ noteId: noteId,
+ hasBlock: hasBlock,
+ }
+
+ if noteId > 0 {
+ // reusing the link field for the id since footnotes don't have links
+ ref.link = data[idOffset:idEnd]
+ // if footnote, it's not really a title, it's the contained text
+ ref.title = raw
+ } else {
+ ref.link = data[linkOffset:linkEnd]
+ ref.title = data[titleOffset:titleEnd]
+ }
+
+ // id matches are case-insensitive
+ id := string(bytes.ToLower(data[idOffset:idEnd]))
+
+ p.refs[id] = ref
+
+ return lineEnd
+}
+
+func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) {
+ // link: whitespace-free sequence, optionally between angle brackets
+ if data[i] == '<' {
+ i++
+ }
+ linkOffset = i
+ for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' {
+ i++
+ }
+ linkEnd = i
+ if data[linkOffset] == '<' && data[linkEnd-1] == '>' {
+ linkOffset++
+ linkEnd--
+ }
+
+ // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' )
+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
+ i++
+ }
+ if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' {
+ return
+ }
+
+ // compute end-of-line
+ if i >= len(data) || data[i] == '\r' || data[i] == '\n' {
+ lineEnd = i
+ }
+ if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' {
+ lineEnd++
+ }
+
+ // optional (space|tab)* spacer after a newline
+ if lineEnd > 0 {
+ i = lineEnd + 1
+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') {
+ i++
+ }
+ }
+
+ // optional title: any non-newline sequence enclosed in '"() alone on its line
+ if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') {
+ i++
+ titleOffset = i
+
+ // look for EOL
+ for i < len(data) && data[i] != '\n' && data[i] != '\r' {
+ i++
+ }
+ if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' {
+ titleEnd = i + 1
+ } else {
+ titleEnd = i
+ }
+
+ // step back
+ i--
+ for i > titleOffset && (data[i] == ' ' || data[i] == '\t') {
+ i--
+ }
+ if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') {
+ lineEnd = titleEnd
+ titleEnd = i
+ }
+ }
+
+ return
+}
+
+// The first bit of this logic is the same as (*parser).listItem, but the rest
+// is much simpler. This function simply finds the entire block and shifts it
+// over by one tab if it is indeed a block (just returns the line if it's not).
+// blockEnd is the end of the section in the input buffer, and contents is the
+// extracted text that was shifted over one tab. It will need to be rendered at
+// the end of the document.
+func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) {
+ if i == 0 || len(data) == 0 {
+ return
+ }
+
+ // skip leading whitespace on first line
+ for i < len(data) && data[i] == ' ' {
+ i++
+ }
+
+ blockStart = i
+
+ // find the end of the line
+ blockEnd = i
+ for i < len(data) && data[i-1] != '\n' {
+ i++
+ }
+
+ // get working buffer
+ var raw bytes.Buffer
+
+ // put the first line into the working buffer
+ raw.Write(data[blockEnd:i])
+ blockEnd = i
+
+ // process the following lines
+ containsBlankLine := false
+
+gatherLines:
+ for blockEnd < len(data) {
+ i++
+
+ // find the end of this line
+ for i < len(data) && data[i-1] != '\n' {
+ i++
+ }
+
+ // if it is an empty line, guess that it is part of this item
+ // and move on to the next line
+ if p.isEmpty(data[blockEnd:i]) > 0 {
+ containsBlankLine = true
+ blockEnd = i
+ continue
+ }
+
+ n := 0
+ if n = isIndented(data[blockEnd:i], indentSize); n == 0 {
+ // this is the end of the block.
+ // we don't want to include this last line in the index.
+ break gatherLines
+ }
+
+ // if there were blank lines before this one, insert a new one now
+ if containsBlankLine {
+ raw.WriteByte('\n')
+ containsBlankLine = false
+ }
+
+ // get rid of that first tab, write to buffer
+ raw.Write(data[blockEnd+n : i])
+ hasBlock = true
+
+ blockEnd = i
+ }
+
+ if data[blockEnd-1] != '\n' {
+ raw.WriteByte('\n')
+ }
+
+ contents = raw.Bytes()
+
+ return
+}
+
+//
+//
+// Miscellaneous helper functions
+//
+//
+
+// Test if a character is a punctuation symbol.
+// Taken from a private function in regexp in the stdlib.
+func ispunct(c byte) bool {
+ for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") {
+ if c == r {
+ return true
+ }
+ }
+ return false
+}
+
+// Test if a character is a whitespace character.
+func isspace(c byte) bool {
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v'
+}
+
+// Test if a character is letter.
+func isletter(c byte) bool {
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
+}
+
+// Test if a character is a letter or a digit.
+// TODO: check when this is looking for ASCII alnum and when it should use unicode
+func isalnum(c byte) bool {
+ return (c >= '0' && c <= '9') || isletter(c)
+}
+
+// Replace tab characters with spaces, aligning to the next TAB_SIZE column.
+// always ends output with a newline
+func expandTabs(out *bytes.Buffer, line []byte, tabSize int) {
+ // first, check for common cases: no tabs, or only tabs at beginning of line
+ i, prefix := 0, 0
+ slowcase := false
+ for i = 0; i < len(line); i++ {
+ if line[i] == '\t' {
+ if prefix == i {
+ prefix++
+ } else {
+ slowcase = true
+ break
+ }
+ }
+ }
+
+ // no need to decode runes if all tabs are at the beginning of the line
+ if !slowcase {
+ for i = 0; i < prefix*tabSize; i++ {
+ out.WriteByte(' ')
+ }
+ out.Write(line[prefix:])
+ return
+ }
+
+ // the slow case: we need to count runes to figure out how
+ // many spaces to insert for each tab
+ column := 0
+ i = 0
+ for i < len(line) {
+ start := i
+ for i < len(line) && line[i] != '\t' {
+ _, size := utf8.DecodeRune(line[i:])
+ i += size
+ column++
+ }
+
+ if i > start {
+ out.Write(line[start:i])
+ }
+
+ if i >= len(line) {
+ break
+ }
+
+ for {
+ out.WriteByte(' ')
+ column++
+ if column%tabSize == 0 {
+ break
+ }
+ }
+
+ i++
+ }
+}
+
+// Find if a line counts as indented or not.
+// Returns number of characters the indent is (0 = not indented).
+func isIndented(data []byte, indentSize int) int {
+ if len(data) == 0 {
+ return 0
+ }
+ if data[0] == '\t' {
+ return 1
+ }
+ if len(data) < indentSize {
+ return 0
+ }
+ for i := 0; i < indentSize; i++ {
+ if data[i] != ' ' {
+ return 0
+ }
+ }
+ return indentSize
+}
+
+// Create a url-safe slug for fragments
+func slugify(in []byte) []byte {
+ if len(in) == 0 {
+ return in
+ }
+ out := make([]byte, 0, len(in))
+ sym := false
+
+ for _, ch := range in {
+ if isalnum(ch) {
+ sym = false
+ out = append(out, ch)
+ } else if sym {
+ continue
+ } else {
+ out = append(out, '-')
+ sym = true
+ }
+ }
+ var a, b int
+ var ch byte
+ for a, ch = range out {
+ if ch != '-' {
+ break
+ }
+ }
+ for b = len(out) - 1; b > 0; b-- {
+ if out[b] != '-' {
+ break
+ }
+ }
+ return out[a : b+1]
+}
diff --git a/vendor/src/github.com/russross/blackfriday/ref_test.go b/vendor/src/github.com/russross/blackfriday/ref_test.go
new file mode 100644
index 0000000..770439c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/ref_test.go
@@ -0,0 +1,128 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+// Markdown 1.0.3 reference tests
+//
+
+package blackfriday
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+)
+
+func runMarkdownReference(input string, flag int) string {
+ renderer := HtmlRenderer(0, "", "")
+ return string(Markdown([]byte(input), renderer, flag))
+}
+
+func doTestsReference(t *testing.T, files []string, flag int) {
+ // catch and report panics
+ var candidate string
+ defer func() {
+ if err := recover(); err != nil {
+ t.Errorf("\npanic while processing [%#v]\n", candidate)
+ }
+ }()
+
+ for _, basename := range files {
+ filename := filepath.Join("testdata", basename+".text")
+ inputBytes, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
+ continue
+ }
+ input := string(inputBytes)
+
+ filename = filepath.Join("testdata", basename+".html")
+ expectedBytes, err := ioutil.ReadFile(filename)
+ if err != nil {
+ t.Errorf("Couldn't open '%s', error: %v\n", filename, err)
+ continue
+ }
+ expected := string(expectedBytes)
+
+ // fmt.Fprintf(os.Stderr, "processing %s ...", filename)
+ actual := string(runMarkdownReference(input, flag))
+ if actual != expected {
+ t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
+ basename+".text", expected, actual)
+ }
+ // fmt.Fprintf(os.Stderr, " ok\n")
+
+ // now test every prefix of every input to check for
+ // bounds checking
+ if !testing.Short() {
+ start, max := 0, len(input)
+ for end := start + 1; end <= max; end++ {
+ candidate = input[start:end]
+ // fmt.Fprintf(os.Stderr, " %s %d:%d/%d\n", filename, start, end, max)
+ _ = runMarkdownReference(candidate, flag)
+ }
+ }
+ }
+}
+
+func TestReference(t *testing.T) {
+ files := []string{
+ "Amps and angle encoding",
+ "Auto links",
+ "Backslash escapes",
+ "Blockquotes with code blocks",
+ "Code Blocks",
+ "Code Spans",
+ "Hard-wrapped paragraphs with list-like lines",
+ "Horizontal rules",
+ "Inline HTML (Advanced)",
+ "Inline HTML (Simple)",
+ "Inline HTML comments",
+ "Links, inline style",
+ "Links, reference style",
+ "Links, shortcut references",
+ "Literal quotes in titles",
+ "Markdown Documentation - Basics",
+ "Markdown Documentation - Syntax",
+ "Nested blockquotes",
+ "Ordered and unordered lists",
+ "Strong and em together",
+ "Tabs",
+ "Tidyness",
+ }
+ doTestsReference(t, files, 0)
+}
+
+func TestReference_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) {
+ files := []string{
+ "Amps and angle encoding",
+ "Auto links",
+ "Backslash escapes",
+ "Blockquotes with code blocks",
+ "Code Blocks",
+ "Code Spans",
+ "Hard-wrapped paragraphs with list-like lines no empty line before block",
+ "Horizontal rules",
+ "Inline HTML (Advanced)",
+ "Inline HTML (Simple)",
+ "Inline HTML comments",
+ "Links, inline style",
+ "Links, reference style",
+ "Links, shortcut references",
+ "Literal quotes in titles",
+ "Markdown Documentation - Basics",
+ "Markdown Documentation - Syntax",
+ "Nested blockquotes",
+ "Ordered and unordered lists",
+ "Strong and em together",
+ "Tabs",
+ "Tidyness",
+ }
+ doTestsReference(t, files, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK)
+}
diff --git a/vendor/src/github.com/russross/blackfriday/smartypants.go b/vendor/src/github.com/russross/blackfriday/smartypants.go
new file mode 100644
index 0000000..8027571
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/smartypants.go
@@ -0,0 +1,398 @@
+//
+// Blackfriday Markdown Processor
+// Available at http://github.com/russross/blackfriday
+//
+// Copyright © 2011 Russ Ross <russ@russross.com>.
+// Distributed under the Simplified BSD License.
+// See README.md for details.
+//
+
+//
+//
+// SmartyPants rendering
+//
+//
+
+package blackfriday
+
+import (
+ "bytes"
+)
+
+type smartypantsData struct {
+ inSingleQuote bool
+ inDoubleQuote bool
+}
+
+func wordBoundary(c byte) bool {
+ return c == 0 || isspace(c) || ispunct(c)
+}
+
+func tolower(c byte) byte {
+ if c >= 'A' && c <= 'Z' {
+ return c - 'A' + 'a'
+ }
+ return c
+}
+
+func isdigit(c byte) bool {
+ return c >= '0' && c <= '9'
+}
+
+func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool {
+ // edge of the buffer is likely to be a tag that we don't get to see,
+ // so we treat it like text sometimes
+
+ // enumerate all sixteen possibilities for (previousChar, nextChar)
+ // each can be one of {0, space, punct, other}
+ switch {
+ case previousChar == 0 && nextChar == 0:
+ // context is not any help here, so toggle
+ *isOpen = !*isOpen
+ case isspace(previousChar) && nextChar == 0:
+ // [ "] might be [ "<code>foo...]
+ *isOpen = true
+ case ispunct(previousChar) && nextChar == 0:
+ // [!"] hmm... could be [Run!"] or [("<code>...]
+ *isOpen = false
+ case /* isnormal(previousChar) && */ nextChar == 0:
+ // [a"] is probably a close
+ *isOpen = false
+ case previousChar == 0 && isspace(nextChar):
+ // [" ] might be [...foo</code>" ]
+ *isOpen = false
+ case isspace(previousChar) && isspace(nextChar):
+ // [ " ] context is not any help here, so toggle
+ *isOpen = !*isOpen
+ case ispunct(previousChar) && isspace(nextChar):
+ // [!" ] is probably a close
+ *isOpen = false
+ case /* isnormal(previousChar) && */ isspace(nextChar):
+ // [a" ] this is one of the easy cases
+ *isOpen = false
+ case previousChar == 0 && ispunct(nextChar):
+ // ["!] hmm... could be ["$1.95] or [</code>"!...]
+ *isOpen = false
+ case isspace(previousChar) && ispunct(nextChar):
+ // [ "!] looks more like [ "$1.95]
+ *isOpen = true
+ case ispunct(previousChar) && ispunct(nextChar):
+ // [!"!] context is not any help here, so toggle
+ *isOpen = !*isOpen
+ case /* isnormal(previousChar) && */ ispunct(nextChar):
+ // [a"!] is probably a close
+ *isOpen = false
+ case previousChar == 0 /* && isnormal(nextChar) */ :
+ // ["a] is probably an open
+ *isOpen = true
+ case isspace(previousChar) /* && isnormal(nextChar) */ :
+ // [ "a] this is one of the easy cases
+ *isOpen = true
+ case ispunct(previousChar) /* && isnormal(nextChar) */ :
+ // [!"a] is probably an open
+ *isOpen = true
+ default:
+ // [a'b] maybe a contraction?
+ *isOpen = false
+ }
+
+ out.WriteByte('&')
+ if *isOpen {
+ out.WriteByte('l')
+ } else {
+ out.WriteByte('r')
+ }
+ out.WriteByte(quote)
+ out.WriteString("quo;")
+ return true
+}
+
+func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 2 {
+ t1 := tolower(text[1])
+
+ if t1 == '\'' {
+ nextChar := byte(0)
+ if len(text) >= 3 {
+ nextChar = text[2]
+ }
+ if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
+ return 1
+ }
+ }
+
+ if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) {
+ out.WriteString("’")
+ return 0
+ }
+
+ if len(text) >= 3 {
+ t2 := tolower(text[2])
+
+ if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) &&
+ (len(text) < 4 || wordBoundary(text[3])) {
+ out.WriteString("’")
+ return 0
+ }
+ }
+ }
+
+ nextChar := byte(0)
+ if len(text) > 1 {
+ nextChar = text[1]
+ }
+ if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) {
+ return 0
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 3 {
+ t1 := tolower(text[1])
+ t2 := tolower(text[2])
+
+ if t1 == 'c' && t2 == ')' {
+ out.WriteString("©")
+ return 2
+ }
+
+ if t1 == 'r' && t2 == ')' {
+ out.WriteString("®")
+ return 2
+ }
+
+ if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' {
+ out.WriteString("™")
+ return 3
+ }
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 2 {
+ if text[1] == '-' {
+ out.WriteString("—")
+ return 1
+ }
+
+ if wordBoundary(previousChar) && wordBoundary(text[1]) {
+ out.WriteString("–")
+ return 0
+ }
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 3 && text[1] == '-' && text[2] == '-' {
+ out.WriteString("—")
+ return 2
+ }
+ if len(text) >= 2 && text[1] == '-' {
+ out.WriteString("–")
+ return 1
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
+ if bytes.HasPrefix(text, []byte(""")) {
+ nextChar := byte(0)
+ if len(text) >= 7 {
+ nextChar = text[6]
+ }
+ if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
+ return 5
+ }
+ }
+
+ if bytes.HasPrefix(text, []byte("�")) {
+ return 3
+ }
+
+ out.WriteByte('&')
+ return 0
+}
+
+func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ return smartAmpVariant(out, smrt, previousChar, text, 'd')
+}
+
+func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ return smartAmpVariant(out, smrt, previousChar, text, 'a')
+}
+
+func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 3 && text[1] == '.' && text[2] == '.' {
+ out.WriteString("…")
+ return 2
+ }
+
+ if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' {
+ out.WriteString("…")
+ return 4
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if len(text) >= 2 && text[1] == '`' {
+ nextChar := byte(0)
+ if len(text) >= 3 {
+ nextChar = text[2]
+ }
+ if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) {
+ return 1
+ }
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
+ // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b
+ // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8)
+ // and avoid changing dates like 1/23/2005 into fractions.
+ numEnd := 0
+ for len(text) > numEnd && isdigit(text[numEnd]) {
+ numEnd++
+ }
+ if numEnd == 0 {
+ out.WriteByte(text[0])
+ return 0
+ }
+ denStart := numEnd + 1
+ if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 {
+ denStart = numEnd + 3
+ } else if len(text) < numEnd+2 || text[numEnd] != '/' {
+ out.WriteByte(text[0])
+ return 0
+ }
+ denEnd := denStart
+ for len(text) > denEnd && isdigit(text[denEnd]) {
+ denEnd++
+ }
+ if denEnd == denStart {
+ out.WriteByte(text[0])
+ return 0
+ }
+ if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' {
+ out.WriteString("<sup>")
+ out.Write(text[:numEnd])
+ out.WriteString("</sup>⁄<sub>")
+ out.Write(text[denStart:denEnd])
+ out.WriteString("</sub>")
+ return denEnd - 1
+ }
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 {
+ if text[0] == '1' && text[1] == '/' && text[2] == '2' {
+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' {
+ out.WriteString("½")
+ return 2
+ }
+ }
+
+ if text[0] == '1' && text[1] == '/' && text[2] == '4' {
+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') {
+ out.WriteString("¼")
+ return 2
+ }
+ }
+
+ if text[0] == '3' && text[1] == '/' && text[2] == '4' {
+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') {
+ out.WriteString("¾")
+ return 2
+ }
+ }
+ }
+
+ out.WriteByte(text[0])
+ return 0
+}
+
+func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int {
+ nextChar := byte(0)
+ if len(text) > 1 {
+ nextChar = text[1]
+ }
+ if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) {
+ out.WriteString(""")
+ }
+
+ return 0
+}
+
+func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd')
+}
+
+func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a')
+}
+
+func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int {
+ i := 0
+
+ for i < len(text) && text[i] != '>' {
+ i++
+ }
+
+ out.Write(text[:i+1])
+ return i
+}
+
+type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int
+
+type smartypantsRenderer [256]smartCallback
+
+func smartypants(flags int) *smartypantsRenderer {
+ r := new(smartypantsRenderer)
+ if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 {
+ r['"'] = smartDoubleQuote
+ r['&'] = smartAmp
+ } else {
+ r['"'] = smartAngledDoubleQuote
+ r['&'] = smartAmpAngledQuote
+ }
+ r['\''] = smartSingleQuote
+ r['('] = smartParens
+ if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 {
+ r['-'] = smartDash
+ } else {
+ r['-'] = smartDashLatex
+ }
+ r['.'] = smartPeriod
+ if flags&HTML_SMARTYPANTS_FRACTIONS == 0 {
+ r['1'] = smartNumber
+ r['3'] = smartNumber
+ } else {
+ for ch := '1'; ch <= '9'; ch++ {
+ r[ch] = smartNumberGeneric
+ }
+ }
+ r['<'] = smartLeftAngle
+ r['`'] = smartBacktick
+ return r
+}
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
new file mode 100644
index 0000000..483f8ff
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html
@@ -0,0 +1,17 @@
+<p>AT&T has an ampersand in their name.</p>
+
+<p>AT&T is another way to write it.</p>
+
+<p>This & that.</p>
+
+<p>4 < 5.</p>
+
+<p>6 > 5.</p>
+
+<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p>
+
+<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p>
+
+<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
+
+<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
new file mode 100644
index 0000000..0e9527f
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text
@@ -0,0 +1,21 @@
+AT&T has an ampersand in their name.
+
+AT&T is another way to write it.
+
+This & that.
+
+4 < 5.
+
+6 > 5.
+
+Here's a [link] [1] with an ampersand in the URL.
+
+Here's a link with an amersand in the link text: [AT&T] [2].
+
+Here's an inline [link](/script?foo=1&bar=2).
+
+Here's an inline [link](</script?foo=1&bar=2>).
+
+
+[1]: http://example.com/?foo=1&bar=2
+[2]: http://att.com/ "AT&T"
\ No newline at end of file
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html
new file mode 100644
index 0000000..b1791e7
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html
@@ -0,0 +1,18 @@
+<p>Link: <a href="http://example.com/">http://example.com/</a>.</p>
+
+<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p>
+
+<ul>
+<li>In a list?</li>
+<li><a href="http://example.com/">http://example.com/</a></li>
+<li>It should.</li>
+</ul>
+
+<blockquote>
+<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p>
+</blockquote>
+
+<p>Auto-links should not occur here: <code><http://example.com/></code></p>
+
+<pre><code>or here: <http://example.com/>
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text
new file mode 100644
index 0000000..abbc488
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text
@@ -0,0 +1,13 @@
+Link: <http://example.com/>.
+
+With an ampersand: <http://example.com/?foo=1&bar=2>
+
+* In a list?
+* <http://example.com/>
+* It should.
+
+> Blockquoted: <http://example.com/>
+
+Auto-links should not occur here: `<http://example.com/>`
+
+ or here: <http://example.com/>
\ No newline at end of file
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html
new file mode 100644
index 0000000..a73c998
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html
@@ -0,0 +1,123 @@
+<p>These should all get escaped:</p>
+
+<p>Backslash: \</p>
+
+<p>Backtick: `</p>
+
+<p>Asterisk: *</p>
+
+<p>Underscore: _</p>
+
+<p>Left brace: {</p>
+
+<p>Right brace: }</p>
+
+<p>Left bracket: [</p>
+
+<p>Right bracket: ]</p>
+
+<p>Left paren: (</p>
+
+<p>Right paren: )</p>
+
+<p>Greater-than: ></p>
+
+<p>Hash: #</p>
+
+<p>Period: .</p>
+
+<p>Bang: !</p>
+
+<p>Plus: +</p>
+
+<p>Minus: -</p>
+
+<p>Tilde: ~</p>
+
+<p>These should not, because they occur within a code block:</p>
+
+<pre><code>Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+Tilde: \~
+</code></pre>
+
+<p>Nor should these, which occur in code spans:</p>
+
+<p>Backslash: <code>\\</code></p>
+
+<p>Backtick: <code>\`</code></p>
+
+<p>Asterisk: <code>\*</code></p>
+
+<p>Underscore: <code>\_</code></p>
+
+<p>Left brace: <code>\{</code></p>
+
+<p>Right brace: <code>\}</code></p>
+
+<p>Left bracket: <code>\[</code></p>
+
+<p>Right bracket: <code>\]</code></p>
+
+<p>Left paren: <code>\(</code></p>
+
+<p>Right paren: <code>\)</code></p>
+
+<p>Greater-than: <code>\></code></p>
+
+<p>Hash: <code>\#</code></p>
+
+<p>Period: <code>\.</code></p>
+
+<p>Bang: <code>\!</code></p>
+
+<p>Plus: <code>\+</code></p>
+
+<p>Minus: <code>\-</code></p>
+
+<p>Tilde: <code>\~</code></p>
+
+<p>These should get escaped, even though they're matching pairs for
+other Markdown constructs:</p>
+
+<p>*asterisks*</p>
+
+<p>_underscores_</p>
+
+<p>`backticks`</p>
+
+<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p>
+
+<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p>
+
+<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text
new file mode 100644
index 0000000..04c20bd
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text
@@ -0,0 +1,126 @@
+These should all get escaped:
+
+Backslash: \\
+
+Backtick: \`
+
+Asterisk: \*
+
+Underscore: \_
+
+Left brace: \{
+
+Right brace: \}
+
+Left bracket: \[
+
+Right bracket: \]
+
+Left paren: \(
+
+Right paren: \)
+
+Greater-than: \>
+
+Hash: \#
+
+Period: \.
+
+Bang: \!
+
+Plus: \+
+
+Minus: \-
+
+Tilde: \~
+
+
+
+These should not, because they occur within a code block:
+
+ Backslash: \\
+
+ Backtick: \`
+
+ Asterisk: \*
+
+ Underscore: \_
+
+ Left brace: \{
+
+ Right brace: \}
+
+ Left bracket: \[
+
+ Right bracket: \]
+
+ Left paren: \(
+
+ Right paren: \)
+
+ Greater-than: \>
+
+ Hash: \#
+
+ Period: \.
+
+ Bang: \!
+
+ Plus: \+
+
+ Minus: \-
+
+ Tilde: \~
+
+
+Nor should these, which occur in code spans:
+
+Backslash: `\\`
+
+Backtick: `` \` ``
+
+Asterisk: `\*`
+
+Underscore: `\_`
+
+Left brace: `\{`
+
+Right brace: `\}`
+
+Left bracket: `\[`
+
+Right bracket: `\]`
+
+Left paren: `\(`
+
+Right paren: `\)`
+
+Greater-than: `\>`
+
+Hash: `\#`
+
+Period: `\.`
+
+Bang: `\!`
+
+Plus: `\+`
+
+Minus: `\-`
+
+Tilde: `\~`
+
+
+These should get escaped, even though they're matching pairs for
+other Markdown constructs:
+
+\*asterisks\*
+
+\_underscores\_
+
+\`backticks\`
+
+This is a code span with a literal backslash-backtick sequence: `` \` ``
+
+This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.
+
+This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
new file mode 100644
index 0000000..360fa9b
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html
@@ -0,0 +1,15 @@
+<blockquote>
+<p>Example:</p>
+
+<pre><code>sub status {
+ print "working";
+}
+</code></pre>
+
+<p>Or:</p>
+
+<pre><code>sub status {
+ return "working";
+}
+</code></pre>
+</blockquote>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
new file mode 100644
index 0000000..c31d171
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text
@@ -0,0 +1,11 @@
+> Example:
+>
+> sub status {
+> print "working";
+> }
+>
+> Or:
+>
+> sub status {
+> return "working";
+> }
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html
new file mode 100644
index 0000000..32703f5
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html
@@ -0,0 +1,18 @@
+<pre><code>code block on the first line
+</code></pre>
+
+<p>Regular text.</p>
+
+<pre><code>code block indented by spaces
+</code></pre>
+
+<p>Regular text.</p>
+
+<pre><code>the lines in this block
+all contain trailing spaces
+</code></pre>
+
+<p>Regular Text.</p>
+
+<pre><code>code block on the last line
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text
new file mode 100644
index 0000000..b54b092
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text
@@ -0,0 +1,14 @@
+ code block on the first line
+
+Regular text.
+
+ code block indented by spaces
+
+Regular text.
+
+ the lines in this block
+ all contain trailing spaces
+
+Regular Text.
+
+ code block on the last line
\ No newline at end of file
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html
new file mode 100644
index 0000000..ef85f95
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html
@@ -0,0 +1,5 @@
+<p><code><test a="</code> content of attribute <code>"></code></p>
+
+<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p>
+
+<p>Here's how you put <code>`backticks`</code> in a code span.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text
new file mode 100644
index 0000000..750a197
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text
@@ -0,0 +1,6 @@
+`<test a="` content of attribute `">`
+
+Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span>
+
+Here's how you put `` `backticks` `` in a code span.
+
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
new file mode 100644
index 0000000..fc25319
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html
@@ -0,0 +1,14 @@
+<p>In Markdown 1.0.0 and earlier. Version</p>
+
+<ol>
+<li>This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.</li>
+</ol>
+
+<p>Here's one with a bullet.</p>
+
+<ul>
+<li>criminey.</li>
+</ul>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
new file mode 100644
index 0000000..f8a5b27
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text
@@ -0,0 +1,8 @@
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
new file mode 100644
index 0000000..e21ac79
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html
@@ -0,0 +1,8 @@
+<p>In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.</p>
+
+<p>Here's one with a bullet.
+* criminey.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
new file mode 100644
index 0000000..f8a5b27
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text
@@ -0,0 +1,8 @@
+In Markdown 1.0.0 and earlier. Version
+8. This line turns into a list item.
+Because a hard-wrapped line in the
+middle of a paragraph looked like a
+list item.
+
+Here's one with a bullet.
+* criminey.
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html
new file mode 100644
index 0000000..e60d4ba
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html
@@ -0,0 +1,71 @@
+<p>Dashes:</p>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>---
+</code></pre>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>- - -
+</code></pre>
+
+<p>Asterisks:</p>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>***
+</code></pre>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>* * *
+</code></pre>
+
+<p>Underscores:</p>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>___
+</code></pre>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<hr>
+
+<pre><code>_ _ _
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text
new file mode 100644
index 0000000..1594bda
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text
@@ -0,0 +1,67 @@
+Dashes:
+
+---
+
+ ---
+
+ ---
+
+ ---
+
+ ---
+
+- - -
+
+ - - -
+
+ - - -
+
+ - - -
+
+ - - -
+
+
+Asterisks:
+
+***
+
+ ***
+
+ ***
+
+ ***
+
+ ***
+
+* * *
+
+ * * *
+
+ * * *
+
+ * * *
+
+ * * *
+
+
+Underscores:
+
+___
+
+ ___
+
+ ___
+
+ ___
+
+ ___
+
+_ _ _
+
+ _ _ _
+
+ _ _ _
+
+ _ _ _
+
+ _ _ _
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
new file mode 100644
index 0000000..3af9caf
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html
@@ -0,0 +1,15 @@
+<p>Simple block on one line:</p>
+
+<div>foo</div>
+
+<p>And nested without indentation:</p>
+
+<div>
+<div>
+<div>
+foo
+</div>
+<div style=">"/>
+</div>
+<div>bar</div>
+</div>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
new file mode 100644
index 0000000..86b7206
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text
@@ -0,0 +1,15 @@
+Simple block on one line:
+
+<div>foo</div>
+
+And nested without indentation:
+
+<div>
+<div>
+<div>
+foo
+</div>
+<div style=">"/>
+</div>
+<div>bar</div>
+</div>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
new file mode 100644
index 0000000..6bf78f8
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html
@@ -0,0 +1,72 @@
+<p>Here's a simple block:</p>
+
+<div>
+ foo
+</div>
+
+<p>This should be a code block, though:</p>
+
+<pre><code><div>
+ foo
+</div>
+</code></pre>
+
+<p>As should this:</p>
+
+<pre><code><div>foo</div>
+</code></pre>
+
+<p>Now, nested:</p>
+
+<div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+</div>
+
+<p>This should just be an HTML comment:</p>
+
+<!-- Comment -->
+
+<p>Multiline:</p>
+
+<!--
+Blah
+Blah
+-->
+
+<p>Code block:</p>
+
+<pre><code><!-- Comment -->
+</code></pre>
+
+<p>Just plain comment, with trailing spaces on the line:</p>
+
+<!-- foo -->
+
+<p>Code:</p>
+
+<pre><code><hr />
+</code></pre>
+
+<p>Hr's:</p>
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar"/>
+
+<hr class="foo" id="bar" >
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
new file mode 100644
index 0000000..14aa2dc
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text
@@ -0,0 +1,69 @@
+Here's a simple block:
+
+<div>
+ foo
+</div>
+
+This should be a code block, though:
+
+ <div>
+ foo
+ </div>
+
+As should this:
+
+ <div>foo</div>
+
+Now, nested:
+
+<div>
+ <div>
+ <div>
+ foo
+ </div>
+ </div>
+</div>
+
+This should just be an HTML comment:
+
+<!-- Comment -->
+
+Multiline:
+
+<!--
+Blah
+Blah
+-->
+
+Code block:
+
+ <!-- Comment -->
+
+Just plain comment, with trailing spaces on the line:
+
+<!-- foo -->
+
+Code:
+
+ <hr />
+
+Hr's:
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr>
+
+<hr/>
+
+<hr />
+
+<hr class="foo" id="bar" />
+
+<hr class="foo" id="bar"/>
+
+<hr class="foo" id="bar" >
+
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html
new file mode 100644
index 0000000..3f167a1
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html
@@ -0,0 +1,13 @@
+<p>Paragraph one.</p>
+
+<!-- This is a simple comment -->
+
+<!--
+ This is another comment.
+-->
+
+<p>Paragraph two.</p>
+
+<!-- one comment block -- -- with two comments -->
+
+<p>The end.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text
new file mode 100644
index 0000000..41d830d
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text
@@ -0,0 +1,13 @@
+Paragraph one.
+
+<!-- This is a simple comment -->
+
+<!--
+ This is another comment.
+-->
+
+Paragraph two.
+
+<!-- one comment block -- -- with two comments -->
+
+The end.
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html
new file mode 100644
index 0000000..5802f2d
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html
@@ -0,0 +1,11 @@
+<p>Just a <a href="/url/">URL</a>.</p>
+
+<p><a href="/url/" title="title">URL and title</a>.</p>
+
+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p>
+
+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p>
+
+<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p>
+
+<p>[Empty]().</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text
new file mode 100644
index 0000000..09017a9
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text
@@ -0,0 +1,12 @@
+Just a [URL](/url/).
+
+[URL and title](/url/ "title").
+
+[URL and title](/url/ "title preceded by two spaces").
+
+[URL and title](/url/ "title preceded by a tab").
+
+[URL and title](/url/ "title has spaces afterward" ).
+
+
+[Empty]().
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html
new file mode 100644
index 0000000..bebefde
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html
@@ -0,0 +1,52 @@
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+
+<p>Foo <a href="/url/" title="Title">bar</a>.</p>
+
+<p>With <a href="/url/">embedded [brackets]</a>.</p>
+
+<p>Indented <a href="/url">once</a>.</p>
+
+<p>Indented <a href="/url">twice</a>.</p>
+
+<p>Indented <a href="/url">thrice</a>.</p>
+
+<p>Indented [four][] times.</p>
+
+<pre><code>[four]: /url
+</code></pre>
+
+<hr>
+
+<p><a href="foo">this</a> should work</p>
+
+<p>So should <a href="foo">this</a>.</p>
+
+<p>And <a href="foo">this</a>.</p>
+
+<p>And <a href="foo">this</a>.</p>
+
+<p>And <a href="foo">this</a>.</p>
+
+<p>But not [that] [].</p>
+
+<p>Nor [that][].</p>
+
+<p>Nor [that].</p>
+
+<p>[Something in brackets like <a href="foo">this</a> should work]</p>
+
+<p>[Same with <a href="foo">this</a>.]</p>
+
+<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p>
+
+<p>Backslashing should suppress [this] and [this].</p>
+
+<hr>
+
+<p>Here's one where the <a href="/url/">link
+breaks</a> across lines.</p>
+
+<p>Here's another where the <a href="/url/">link
+breaks</a> across lines, but with a line-ending space.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text
new file mode 100644
index 0000000..341ec88
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text
@@ -0,0 +1,71 @@
+Foo [bar] [1].
+
+Foo [bar][1].
+
+Foo [bar]
+[1].
+
+[1]: /url/ "Title"
+
+
+With [embedded [brackets]] [b].
+
+
+Indented [once][].
+
+Indented [twice][].
+
+Indented [thrice][].
+
+Indented [four][] times.
+
+ [once]: /url
+
+ [twice]: /url
+
+ [thrice]: /url
+
+ [four]: /url
+
+
+[b]: /url/
+
+* * *
+
+[this] [this] should work
+
+So should [this][this].
+
+And [this] [].
+
+And [this][].
+
+And [this].
+
+But not [that] [].
+
+Nor [that][].
+
+Nor [that].
+
+[Something in brackets like [this][] should work]
+
+[Same with [this].]
+
+In this case, [this](/somethingelse/) points to something else.
+
+Backslashing should suppress \[this] and [this\].
+
+[this]: foo
+
+
+* * *
+
+Here's one where the [link
+breaks] across lines.
+
+Here's another where the [link
+breaks] across lines, but with a line-ending space.
+
+
+[link breaks]: /url/
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html
new file mode 100644
index 0000000..0b5e1d6
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html
@@ -0,0 +1,9 @@
+<p>This is the <a href="/simple">simple case</a>.</p>
+
+<p>This one has a <a href="/foo">line
+break</a>.</p>
+
+<p>This one has a <a href="/foo">line
+break</a> with a line-ending space.</p>
+
+<p><a href="/that">this</a> and the <a href="/other">other</a></p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text
new file mode 100644
index 0000000..8c44c98
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text
@@ -0,0 +1,20 @@
+This is the [simple case].
+
+[simple case]: /simple
+
+
+
+This one has a [line
+break].
+
+This one has a [line
+break] with a line-ending space.
+
+[line break]: /foo
+
+
+[this] [that] and the [other]
+
+[this]: /this
+[that]: /that
+[other]: /other
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
new file mode 100644
index 0000000..611c1ac
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html
@@ -0,0 +1,3 @@
+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
+
+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
new file mode 100644
index 0000000..29d0e42
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text
@@ -0,0 +1,7 @@
+Foo [bar][].
+
+Foo [bar](/url/ "Title with "quotes" inside").
+
+
+ [bar]: /url/ "Title with "quotes" inside"
+
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
new file mode 100644
index 0000000..ea3a61c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html
@@ -0,0 +1,314 @@
+<h1>Markdown: Basics</h1>
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a class="selected" title="Markdown Basics">Basics</a></li>
+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+<h2>Getting the Gist of Markdown's Formatting Syntax</h2>
+
+<p>This page offers a brief overview of what it's like to use Markdown.
+The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for
+every feature, but Markdown should be very easy to pick up simply by
+looking at a few examples of it in action. The examples on this page
+are written in a before/after style, showing example syntax and the
+HTML output produced by Markdown.</p>
+
+<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a
+web application that allows you type your own Markdown-formatted text
+and translate it to XHTML.</p>
+
+<p><strong>Note:</strong> This document is itself written using Markdown; you
+can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p>
+
+<h2>Paragraphs, Headers, Blockquotes</h2>
+
+<p>A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+
+<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>.
+Setext-style headers for <code><h1></code> and <code><h2></code> are created by
+"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively.
+To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the
+beginning of the line -- the number of hashes equals the resulting
+HTML header level.</p>
+
+<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p>
+
+<p>Markdown:</p>
+
+<pre><code>A First Level Header
+====================
+
+A Second Level Header
+---------------------
+
+Now is the time for all good men to come to
+the aid of their country. This is just a
+regular paragraph.
+
+The quick brown fox jumped over the lazy
+dog's back.
+
+### Header 3
+
+> This is a blockquote.
+>
+> This is the second paragraph in the blockquote.
+>
+> ## This is an H2 in a blockquote
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><h1>A First Level Header</h1>
+
+<h2>A Second Level Header</h2>
+
+<p>Now is the time for all good men to come to
+the aid of their country. This is just a
+regular paragraph.</p>
+
+<p>The quick brown fox jumped over the lazy
+dog's back.</p>
+
+<h3>Header 3</h3>
+
+<blockquote>
+ <p>This is a blockquote.</p>
+
+ <p>This is the second paragraph in the blockquote.</p>
+
+ <h2>This is an H2 in a blockquote</h2>
+</blockquote>
+</code></pre>
+
+<h3>Phrase Emphasis</h3>
+
+<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p>
+
+<p>Markdown:</p>
+
+<pre><code>Some of these words *are emphasized*.
+Some of these words _are emphasized also_.
+
+Use two asterisks for **strong emphasis**.
+Or, if you prefer, __use two underscores instead__.
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>Some of these words <em>are emphasized</em>.
+Some of these words <em>are emphasized also</em>.</p>
+
+<p>Use two asterisks for <strong>strong emphasis</strong>.
+Or, if you prefer, <strong>use two underscores instead</strong>.</p>
+</code></pre>
+
+<h2>Lists</h2>
+
+<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>,
+<code>+</code>, and <code>-</code>) as list markers. These three markers are
+interchangable; this:</p>
+
+<pre><code>* Candy.
+* Gum.
+* Booze.
+</code></pre>
+
+<p>this:</p>
+
+<pre><code>+ Candy.
++ Gum.
++ Booze.
+</code></pre>
+
+<p>and this:</p>
+
+<pre><code>- Candy.
+- Gum.
+- Booze.
+</code></pre>
+
+<p>all produce the same output:</p>
+
+<pre><code><ul>
+<li>Candy.</li>
+<li>Gum.</li>
+<li>Booze.</li>
+</ul>
+</code></pre>
+
+<p>Ordered (numbered) lists use regular numbers, followed by periods, as
+list markers:</p>
+
+<pre><code>1. Red
+2. Green
+3. Blue
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><ol>
+<li>Red</li>
+<li>Green</li>
+<li>Blue</li>
+</ol>
+</code></pre>
+
+<p>If you put blank lines between items, you'll get <code><p></code> tags for the
+list item text. You can create multi-paragraph list items by indenting
+the paragraphs by 4 spaces or 1 tab:</p>
+
+<pre><code>* A list item.
+
+ With multiple paragraphs.
+
+* Another item in the list.
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><ul>
+<li><p>A list item.</p>
+<p>With multiple paragraphs.</p></li>
+<li><p>Another item in the list.</p></li>
+</ul>
+</code></pre>
+
+<h3>Links</h3>
+
+<p>Markdown supports two styles for creating links: <em>inline</em> and
+<em>reference</em>. With both styles, you use square brackets to delimit the
+text you want to turn into a link.</p>
+
+<p>Inline-style links use parentheses immediately after the link text.
+For example:</p>
+
+<pre><code>This is an [example link](http://example.com/).
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>This is an <a href="http://example.com/">
+example link</a>.</p>
+</code></pre>
+
+<p>Optionally, you may include a title attribute in the parentheses:</p>
+
+<pre><code>This is an [example link](http://example.com/ "With a Title").
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>This is an <a href="http://example.com/" title="With a Title">
+example link</a>.</p>
+</code></pre>
+
+<p>Reference-style links allow you to refer to your links by names, which
+you define elsewhere in your document:</p>
+
+<pre><code>I get 10 times more traffic from [Google][1] than from
+[Yahoo][2] or [MSN][3].
+
+[1]: http://google.com/ "Google"
+[2]: http://search.yahoo.com/ "Yahoo Search"
+[3]: http://search.msn.com/ "MSN Search"
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
+title="Google">Google</a> than from <a href="http://search.yahoo.com/"
+title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
+title="MSN Search">MSN</a>.</p>
+</code></pre>
+
+<p>The title attribute is optional. Link names may contain letters,
+numbers and spaces, but are <em>not</em> case sensitive:</p>
+
+<pre><code>I start my morning with a cup of coffee and
+[The New York Times][NY Times].
+
+[ny times]: http://www.nytimes.com/
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>I start my morning with a cup of coffee and
+<a href="http://www.nytimes.com/">The New York Times</a>.</p>
+</code></pre>
+
+<h3>Images</h3>
+
+<p>Image syntax is very much like link syntax.</p>
+
+<p>Inline (titles are optional):</p>
+
+<pre><code>![alt text](/path/to/img.jpg "Title")
+</code></pre>
+
+<p>Reference-style:</p>
+
+<pre><code>![alt text][id]
+
+[id]: /path/to/img.jpg "Title"
+</code></pre>
+
+<p>Both of the above examples produce the same output:</p>
+
+<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" />
+</code></pre>
+
+<h3>Code</h3>
+
+<p>In a regular paragraph, you can create code span by wrapping text in
+backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or
+<code>></code>) will automatically be translated into HTML entities. This makes
+it easy to use Markdown to write about HTML example code:</p>
+
+<pre><code>I strongly recommend against using any `<blink>` tags.
+
+I wish SmartyPants used named entities like `&mdash;`
+instead of decimal-encoded entites like `&#8212;`.
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>I strongly recommend against using any
+<code>&lt;blink&gt;</code> tags.</p>
+
+<p>I wish SmartyPants used named entities like
+<code>&amp;mdash;</code> instead of decimal-encoded
+entites like <code>&amp;#8212;</code>.</p>
+</code></pre>
+
+<p>To specify an entire block of pre-formatted code, indent every line of
+the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>,
+and <code>></code> characters will be escaped automatically.</p>
+
+<p>Markdown:</p>
+
+<pre><code>If you want your page to validate under XHTML 1.0 Strict,
+you've got to put paragraph tags in your blockquotes:
+
+ <blockquote>
+ <p>For example.</p>
+ </blockquote>
+</code></pre>
+
+<p>Output:</p>
+
+<pre><code><p>If you want your page to validate under XHTML 1.0 Strict,
+you've got to put paragraph tags in your blockquotes:</p>
+
+<pre><code>&lt;blockquote&gt;
+ &lt;p&gt;For example.&lt;/p&gt;
+&lt;/blockquote&gt;
+</code></pre>
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
new file mode 100644
index 0000000..486055c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text
@@ -0,0 +1,306 @@
+Markdown: Basics
+================
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a class="selected" title="Markdown Basics">Basics</a></li>
+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+
+Getting the Gist of Markdown's Formatting Syntax
+------------------------------------------------
+
+This page offers a brief overview of what it's like to use Markdown.
+The [syntax page] [s] provides complete, detailed documentation for
+every feature, but Markdown should be very easy to pick up simply by
+looking at a few examples of it in action. The examples on this page
+are written in a before/after style, showing example syntax and the
+HTML output produced by Markdown.
+
+It's also helpful to simply try Markdown out; the [Dingus] [d] is a
+web application that allows you type your own Markdown-formatted text
+and translate it to XHTML.
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL] [src].
+
+ [s]: /projects/markdown/syntax "Markdown Syntax"
+ [d]: /projects/markdown/dingus "Markdown Dingus"
+ [src]: /projects/markdown/basics.text
+
+
+## Paragraphs, Headers, Blockquotes ##
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.
+
+Markdown offers two styles of headers: *Setext* and *atx*.
+Setext-style headers for `<h1>` and `<h2>` are created by
+"underlining" with equal signs (`=`) and hyphens (`-`), respectively.
+To create an atx-style header, you put 1-6 hash marks (`#`) at the
+beginning of the line -- the number of hashes equals the resulting
+HTML header level.
+
+Blockquotes are indicated using email-style '`>`' angle brackets.
+
+Markdown:
+
+ A First Level Header
+ ====================
+
+ A Second Level Header
+ ---------------------
+
+ Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.
+
+ The quick brown fox jumped over the lazy
+ dog's back.
+
+ ### Header 3
+
+ > This is a blockquote.
+ >
+ > This is the second paragraph in the blockquote.
+ >
+ > ## This is an H2 in a blockquote
+
+
+Output:
+
+ <h1>A First Level Header</h1>
+
+ <h2>A Second Level Header</h2>
+
+ <p>Now is the time for all good men to come to
+ the aid of their country. This is just a
+ regular paragraph.</p>
+
+ <p>The quick brown fox jumped over the lazy
+ dog's back.</p>
+
+ <h3>Header 3</h3>
+
+ <blockquote>
+ <p>This is a blockquote.</p>
+
+ <p>This is the second paragraph in the blockquote.</p>
+
+ <h2>This is an H2 in a blockquote</h2>
+ </blockquote>
+
+
+
+### Phrase Emphasis ###
+
+Markdown uses asterisks and underscores to indicate spans of emphasis.
+
+Markdown:
+
+ Some of these words *are emphasized*.
+ Some of these words _are emphasized also_.
+
+ Use two asterisks for **strong emphasis**.
+ Or, if you prefer, __use two underscores instead__.
+
+Output:
+
+ <p>Some of these words <em>are emphasized</em>.
+ Some of these words <em>are emphasized also</em>.</p>
+
+ <p>Use two asterisks for <strong>strong emphasis</strong>.
+ Or, if you prefer, <strong>use two underscores instead</strong>.</p>
+
+
+
+## Lists ##
+
+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`,
+`+`, and `-`) as list markers. These three markers are
+interchangable; this:
+
+ * Candy.
+ * Gum.
+ * Booze.
+
+this:
+
+ + Candy.
+ + Gum.
+ + Booze.
+
+and this:
+
+ - Candy.
+ - Gum.
+ - Booze.
+
+all produce the same output:
+
+ <ul>
+ <li>Candy.</li>
+ <li>Gum.</li>
+ <li>Booze.</li>
+ </ul>
+
+Ordered (numbered) lists use regular numbers, followed by periods, as
+list markers:
+
+ 1. Red
+ 2. Green
+ 3. Blue
+
+Output:
+
+ <ol>
+ <li>Red</li>
+ <li>Green</li>
+ <li>Blue</li>
+ </ol>
+
+If you put blank lines between items, you'll get `<p>` tags for the
+list item text. You can create multi-paragraph list items by indenting
+the paragraphs by 4 spaces or 1 tab:
+
+ * A list item.
+
+ With multiple paragraphs.
+
+ * Another item in the list.
+
+Output:
+
+ <ul>
+ <li><p>A list item.</p>
+ <p>With multiple paragraphs.</p></li>
+ <li><p>Another item in the list.</p></li>
+ </ul>
+
+
+
+### Links ###
+
+Markdown supports two styles for creating links: *inline* and
+*reference*. With both styles, you use square brackets to delimit the
+text you want to turn into a link.
+
+Inline-style links use parentheses immediately after the link text.
+For example:
+
+ This is an [example link](http://example.com/).
+
+Output:
+
+ <p>This is an <a href="http://example.com/">
+ example link</a>.</p>
+
+Optionally, you may include a title attribute in the parentheses:
+
+ This is an [example link](http://example.com/ "With a Title").
+
+Output:
+
+ <p>This is an <a href="http://example.com/" title="With a Title">
+ example link</a>.</p>
+
+Reference-style links allow you to refer to your links by names, which
+you define elsewhere in your document:
+
+ I get 10 times more traffic from [Google][1] than from
+ [Yahoo][2] or [MSN][3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Output:
+
+ <p>I get 10 times more traffic from <a href="http://google.com/"
+ title="Google">Google</a> than from <a href="http://search.yahoo.com/"
+ title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
+ title="MSN Search">MSN</a>.</p>
+
+The title attribute is optional. Link names may contain letters,
+numbers and spaces, but are *not* case sensitive:
+
+ I start my morning with a cup of coffee and
+ [The New York Times][NY Times].
+
+ [ny times]: http://www.nytimes.com/
+
+Output:
+
+ <p>I start my morning with a cup of coffee and
+ <a href="http://www.nytimes.com/">The New York Times</a>.</p>
+
+
+### Images ###
+
+Image syntax is very much like link syntax.
+
+Inline (titles are optional):
+
+ ![alt text](/path/to/img.jpg "Title")
+
+Reference-style:
+
+ ![alt text][id]
+
+ [id]: /path/to/img.jpg "Title"
+
+Both of the above examples produce the same output:
+
+ <img src="/path/to/img.jpg" alt="alt text" title="Title" />
+
+
+
+### Code ###
+
+In a regular paragraph, you can create code span by wrapping text in
+backtick quotes. Any ampersands (`&`) and angle brackets (`<` or
+`>`) will automatically be translated into HTML entities. This makes
+it easy to use Markdown to write about HTML example code:
+
+ I strongly recommend against using any `<blink>` tags.
+
+ I wish SmartyPants used named entities like `—`
+ instead of decimal-encoded entites like `—`.
+
+Output:
+
+ <p>I strongly recommend against using any
+ <code><blink></code> tags.</p>
+
+ <p>I wish SmartyPants used named entities like
+ <code>&mdash;</code> instead of decimal-encoded
+ entites like <code>&#8212;</code>.</p>
+
+
+To specify an entire block of pre-formatted code, indent every line of
+the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`,
+and `>` characters will be escaped automatically.
+
+Markdown:
+
+ If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:
+
+ <blockquote>
+ <p>For example.</p>
+ </blockquote>
+
+Output:
+
+ <p>If you want your page to validate under XHTML 1.0 Strict,
+ you've got to put paragraph tags in your blockquotes:</p>
+
+ <pre><code><blockquote>
+ <p>For example.</p>
+ </blockquote>
+ </code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
new file mode 100644
index 0000000..61dde59
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html
@@ -0,0 +1,946 @@
+<h1>Markdown: Syntax</h1>
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+<ul>
+<li><a href="#overview">Overview</a>
+
+<ul>
+<li><a href="#philosophy">Philosophy</a></li>
+<li><a href="#html">Inline HTML</a></li>
+<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li>
+</ul></li>
+<li><a href="#block">Block Elements</a>
+
+<ul>
+<li><a href="#p">Paragraphs and Line Breaks</a></li>
+<li><a href="#header">Headers</a></li>
+<li><a href="#blockquote">Blockquotes</a></li>
+<li><a href="#list">Lists</a></li>
+<li><a href="#precode">Code Blocks</a></li>
+<li><a href="#hr">Horizontal Rules</a></li>
+</ul></li>
+<li><a href="#span">Span Elements</a>
+
+<ul>
+<li><a href="#link">Links</a></li>
+<li><a href="#em">Emphasis</a></li>
+<li><a href="#code">Code</a></li>
+<li><a href="#img">Images</a></li>
+</ul></li>
+<li><a href="#misc">Miscellaneous</a>
+
+<ul>
+<li><a href="#backslash">Backslash Escapes</a></li>
+<li><a href="#autolink">Automatic Links</a></li>
+</ul></li>
+</ul>
+
+<p><strong>Note:</strong> This document is itself written using Markdown; you
+can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p>
+
+<hr>
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p>
+
+<p>Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it's been marked up with tags or formatting instructions. While
+Markdown's syntax has been influenced by several existing text-to-HTML
+filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>,
+<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.</p>
+
+<p>To this end, Markdown's syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like *emphasis*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you've ever
+used email.</p>
+
+<h3 id="html">Inline HTML</h3>
+
+<p>Markdown's syntax is intended for one purpose: to be used as a
+format for <em>writing</em> for the web.</p>
+
+<p>Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is <em>not</em> to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em>
+format. Thus, Markdown's formatting syntax only addresses issues that
+can be conveyed in plain text.</p>
+
+<p>For any markup that is not covered by Markdown's syntax, you simply
+use HTML itself. There's no need to preface it or delimit it to
+indicate that you're switching from Markdown to HTML; you just use
+the tags.</p>
+
+<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>,
+<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p>
+
+<p>For example, to add an HTML table to a Markdown article:</p>
+
+<pre><code>This is a regular paragraph.
+
+<table>
+ <tr>
+ <td>Foo</td>
+ </tr>
+</table>
+
+This is another regular paragraph.
+</code></pre>
+
+<p>Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an
+HTML block.</p>
+
+<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's
+link or image syntax, go right ahead.</p>
+
+<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within
+span-level tags.</p>
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+<p>In HTML, there are two characters that demand special treatment: <code><</code>
+and <code>&</code>. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. <code>&lt;</code>, and
+<code>&amp;</code>.</p>
+
+<p>Ampersands in particular are bedeviling for web writers. If you want to
+write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to
+escape ampersands within URLs. Thus, if you want to link to:</p>
+
+<pre><code>http://images.google.com/images?num=30&q=larry+bird
+</code></pre>
+
+<p>you need to encode the URL as:</p>
+
+<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird
+</code></pre>
+
+<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.</p>
+
+<p>Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into <code>&amp;</code>.</p>
+
+<p>So, if you want to include a copyright symbol in your article, you can write:</p>
+
+<pre><code>&copy;
+</code></pre>
+
+<p>and Markdown will leave it alone. But if you write:</p>
+
+<pre><code>AT&T
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>AT&amp;T
+</code></pre>
+
+<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:</p>
+
+<pre><code>4 < 5
+</code></pre>
+
+<p>Markdown will translate it to:</p>
+
+<pre><code>4 &lt; 5
+</code></pre>
+
+<p>However, inside Markdown code spans and blocks, angle brackets and
+ampersands are <em>always</em> encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single <code><</code>
+and <code>&</code> in your example code needs to be escaped.)</p>
+
+<hr>
+
+<h2 id="block">Block Elements</h2>
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+<p>A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing but spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.</p>
+
+<p>The implication of the "one or more consecutive lines of text" rule is
+that Markdown supports "hard-wrapped" text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type's "Convert Line Breaks" option) which translate every line break
+character in a paragraph into a <code><br /></code> tag.</p>
+
+<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you
+end a line with two or more spaces, then type return.</p>
+
+<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic
+"every line break is a <code><br /></code>" rule wouldn't work for Markdown.
+Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a>
+work best -- and look better -- when you format them with hard breaks.</p>
+
+<h3 id="header">Headers</h3>
+
+<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p>
+
+<p>Setext-style headers are "underlined" using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:</p>
+
+<pre><code>This is an H1
+=============
+
+This is an H2
+-------------
+</code></pre>
+
+<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p>
+
+<p>Atx-style headers use 1-6 hash characters at the start of the line,
+corresponding to header levels 1-6. For example:</p>
+
+<pre><code># This is an H1
+
+## This is an H2
+
+###### This is an H6
+</code></pre>
+
+<p>Optionally, you may "close" atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :</p>
+
+<pre><code># This is an H1 #
+
+## This is an H2 ##
+
+### This is an H3 ######
+</code></pre>
+
+<h3 id="blockquote">Blockquotes</h3>
+
+<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a <code>></code> before every line:</p>
+
+<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+>
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+> id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Markdown allows you to be lazy and only put the <code>></code> before the first
+line of a hard-wrapped paragraph:</p>
+
+<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of <code>></code>:</p>
+
+<pre><code>> This is the first level of quoting.
+>
+> > This is nested blockquote.
+>
+> Back to the first level.
+</code></pre>
+
+<p>Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:</p>
+
+<pre><code>> ## This is a header.
+>
+> 1. This is the first list item.
+> 2. This is the second list item.
+>
+> Here's some example code:
+>
+> return shell_exec("echo $input | $markdown_script");
+</code></pre>
+
+<p>Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.</p>
+
+<h3 id="list">Lists</h3>
+
+<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p>
+
+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:</p>
+
+<pre><code>* Red
+* Green
+* Blue
+</code></pre>
+
+<p>is equivalent to:</p>
+
+<pre><code>+ Red
++ Green
++ Blue
+</code></pre>
+
+<p>and:</p>
+
+<pre><code>- Red
+- Green
+- Blue
+</code></pre>
+
+<p>Ordered lists use numbers followed by periods:</p>
+
+<pre><code>1. Bird
+2. McHale
+3. Parish
+</code></pre>
+
+<p>It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:</p>
+
+<pre><code><ol>
+<li>Bird</li>
+<li>McHale</li>
+<li>Parish</li>
+</ol>
+</code></pre>
+
+<p>If you instead wrote the list in Markdown like this:</p>
+
+<pre><code>1. Bird
+1. McHale
+1. Parish
+</code></pre>
+
+<p>or even:</p>
+
+<pre><code>3. Bird
+1. McHale
+8. Parish
+</code></pre>
+
+<p>you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.</p>
+
+<p>If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.</p>
+
+<p>List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.</p>
+
+<p>To make lists look nice, you can wrap items with hanging indents:</p>
+
+<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>But if you want to be lazy, you don't have to:</p>
+
+<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+viverra nec, fringilla in, laoreet vitae, risus.
+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>If list items are separated by blank lines, Markdown will wrap the
+items in <code><p></code> tags in the HTML output. For example, this input:</p>
+
+<pre><code>* Bird
+* Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code><ul>
+<li>Bird</li>
+<li>Magic</li>
+</ul>
+</code></pre>
+
+<p>But this:</p>
+
+<pre><code>* Bird
+
+* Magic
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code><ul>
+<li><p>Bird</p></li>
+<li><p>Magic</p></li>
+</ul>
+</code></pre>
+
+<p>List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be intended by either 4 spaces
+or one tab:</p>
+
+<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+ mi posuere lectus.
+
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+ sit amet velit.
+
+2. Suspendisse id sem consectetuer libero luctus adipiscing.
+</code></pre>
+
+<p>It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:</p>
+
+<pre><code>* This is a list item with two paragraphs.
+
+ This is the second paragraph in the list item. You're
+only required to indent the first line. Lorem ipsum dolor
+sit amet, consectetuer adipiscing elit.
+
+* Another item in the same list.
+</code></pre>
+
+<p>To put a blockquote within a list item, the blockquote's <code>></code>
+delimiters need to be indented:</p>
+
+<pre><code>* A list item with a blockquote:
+
+ > This is a blockquote
+ > inside a list item.
+</code></pre>
+
+<p>To put a code block within a list item, the code block needs
+to be indented <em>twice</em> -- 8 spaces or two tabs:</p>
+
+<pre><code>* A list item with a code block:
+
+ <code goes here>
+</code></pre>
+
+<p>It's worth noting that it's possible to trigger an ordered list by
+accident, by writing something like this:</p>
+
+<pre><code>1986. What a great season.
+</code></pre>
+
+<p>In other words, a <em>number-period-space</em> sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:</p>
+
+<pre><code>1986\. What a great season.
+</code></pre>
+
+<h3 id="precode">Code Blocks</h3>
+
+<p>Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both <code><pre></code> and <code><code></code> tags.</p>
+
+<p>To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:</p>
+
+<pre><code>This is a normal paragraph:
+
+ This is a code block.
+</code></pre>
+
+<p>Markdown will generate:</p>
+
+<pre><code><p>This is a normal paragraph:</p>
+
+<pre><code>This is a code block.
+</code></pre>
+</code></pre>
+
+<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each
+line of the code block. For example, this:</p>
+
+<pre><code>Here is an example of AppleScript:
+
+ tell application "Foo"
+ beep
+ end tell
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code><p>Here is an example of AppleScript:</p>
+
+<pre><code>tell application "Foo"
+ beep
+end tell
+</code></pre>
+</code></pre>
+
+<p>A code block continues until it reaches a line that is not indented
+(or the end of the article).</p>
+
+<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:</p>
+
+<pre><code> <div class="footer">
+ &copy; 2004 Foo Corporation
+ </div>
+</code></pre>
+
+<p>will turn into:</p>
+
+<pre><code><pre><code>&lt;div class="footer"&gt;
+ &amp;copy; 2004 Foo Corporation
+&lt;/div&gt;
+</code></pre>
+</code></pre>
+
+<p>Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.</p>
+
+<h3 id="hr">Horizontal Rules</h3>
+
+<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:</p>
+
+<pre><code>* * *
+
+***
+
+*****
+
+- - -
+
+---------------------------------------
+
+_ _ _
+</code></pre>
+
+<hr>
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p>
+
+<p>In both styles, the link text is delimited by [square brackets].</p>
+
+<p>To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an <em>optional</em>
+title for the link, surrounded in quotes. For example:</p>
+
+<pre><code>This is [an example](http://example.com/ "Title") inline link.
+
+[This link](http://example.net/) has no title attribute.
+</code></pre>
+
+<p>Will produce:</p>
+
+<pre><code><p>This is <a href="http://example.com/" title="Title">
+an example</a> inline link.</p>
+
+<p><a href="http://example.net/">This link</a> has no
+title attribute.</p>
+</code></pre>
+
+<p>If you're referring to a local resource on the same server, you can
+use relative paths:</p>
+
+<pre><code>See my [About](/about/) page for details.
+</code></pre>
+
+<p>Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:</p>
+
+<pre><code>This is [an example][id] reference-style link.
+</code></pre>
+
+<p>You can optionally use a space to separate the sets of brackets:</p>
+
+<pre><code>This is [an example] [id] reference-style link.
+</code></pre>
+
+<p>Then, anywhere in the document, you define your link label like this,
+on a line by itself:</p>
+
+<pre><code>[id]: http://example.com/ "Optional Title Here"
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>Square brackets containing the link identifier (optionally
+indented from the left margin using up to three spaces);</li>
+<li>followed by a colon;</li>
+<li>followed by one or more spaces (or tabs);</li>
+<li>followed by the URL for the link;</li>
+<li>optionally followed by a title attribute for the link, enclosed
+in double or single quotes.</li>
+</ul>
+
+<p>The link URL may, optionally, be surrounded by angle brackets:</p>
+
+<pre><code>[id]: <http://example.com/> "Optional Title Here"
+</code></pre>
+
+<p>You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:</p>
+
+<pre><code>[id]: http://example.com/longish/path/to/resource/here
+ "Optional Title Here"
+</code></pre>
+
+<p>Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.</p>
+
+<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p>
+
+<pre><code>[link text][a]
+[link text][A]
+</code></pre>
+
+<p>are equivalent.</p>
+
+<p>The <em>implicit link name</em> shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets -- e.g., to link the word
+"Google" to the google.com web site, you could simply write:</p>
+
+<pre><code>[Google][]
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Google]: http://google.com/
+</code></pre>
+
+<p>Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:</p>
+
+<pre><code>Visit [Daring Fireball][] for more information.
+</code></pre>
+
+<p>And then define the link:</p>
+
+<pre><code>[Daring Fireball]: http://daringfireball.net/
+</code></pre>
+
+<p>Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they're
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.</p>
+
+<p>Here's an example of reference links in action:</p>
+
+<pre><code>I get 10 times more traffic from [Google] [1] than from
+[Yahoo] [2] or [MSN] [3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+</code></pre>
+
+<p>Using the implicit link name shortcut, you could instead write:</p>
+
+<pre><code>I get 10 times more traffic from [Google][] than from
+[Yahoo][] or [MSN][].
+
+ [google]: http://google.com/ "Google"
+ [yahoo]: http://search.yahoo.com/ "Yahoo Search"
+ [msn]: http://search.msn.com/ "MSN Search"
+</code></pre>
+
+<p>Both of the above examples will produce the following HTML output:</p>
+
+<pre><code><p>I get 10 times more traffic from <a href="http://google.com/"
+title="Google">Google</a> than from
+<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
+or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+</code></pre>
+
+<p>For comparison, here is the same paragraph written using
+Markdown's inline link style:</p>
+
+<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google")
+than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
+[MSN](http://search.msn.com/ "MSN Search").
+</code></pre>
+
+<p>The point of reference-style links is not that they're easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it's 176 characters; and as raw HTML,
+it's 234 characters. In the raw HTML, there's more markup than there
+is text.</p>
+
+<p>With Markdown's reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.</p>
+
+<h3 id="em">Emphasis</h3>
+
+<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of
+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an
+HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML
+<code><strong></code> tag. E.g., this input:</p>
+
+<pre><code>*single asterisks*
+
+_single underscores_
+
+**double asterisks**
+
+__double underscores__
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code><em>single asterisks</em>
+
+<em>single underscores</em>
+
+<strong>double asterisks</strong>
+
+<strong>double underscores</strong>
+</code></pre>
+
+<p>You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.</p>
+
+<p>Emphasis can be used in the middle of a word:</p>
+
+<pre><code>un*fucking*believable
+</code></pre>
+
+<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a
+literal asterisk or underscore.</p>
+
+<p>To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:</p>
+
+<pre><code>\*this text is surrounded by literal asterisks\*
+</code></pre>
+
+<h3 id="code">Code</h3>
+
+<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:</p>
+
+<pre><code>Use the `printf()` function.
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code><p>Use the <code>printf()</code> function.</p>
+</code></pre>
+
+<p>To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:</p>
+
+<pre><code>``There is a literal backtick (`) here.``
+</code></pre>
+
+<p>which will produce this:</p>
+
+<pre><code><p><code>There is a literal backtick (`) here.</code></p>
+</code></pre>
+
+<p>The backtick delimiters surrounding a code span may include spaces --
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:</p>
+
+<pre><code>A single backtick in a code span: `` ` ``
+
+A backtick-delimited string in a code span: `` `foo` ``
+</code></pre>
+
+<p>will produce:</p>
+
+<pre><code><p>A single backtick in a code span: <code>`</code></p>
+
+<p>A backtick-delimited string in a code span: <code>`foo`</code></p>
+</code></pre>
+
+<p>With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:</p>
+
+<pre><code>Please don't use any `<blink>` tags.
+</code></pre>
+
+<p>into:</p>
+
+<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
+</code></pre>
+
+<p>You can write this:</p>
+
+<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`.
+</code></pre>
+
+<p>to produce:</p>
+
+<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded
+equivalent of <code>&amp;mdash;</code>.</p>
+</code></pre>
+
+<h3 id="img">Images</h3>
+
+<p>Admittedly, it's fairly difficult to devise a "natural" syntax for
+placing images into a plain text document format.</p>
+
+<p>Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p>
+
+<p>Inline image syntax looks like this:</p>
+
+<pre><code>![Alt text](/path/to/img.jpg)
+
+![Alt text](/path/to/img.jpg "Optional title")
+</code></pre>
+
+<p>That is:</p>
+
+<ul>
+<li>An exclamation mark: <code>!</code>;</li>
+<li>followed by a set of square brackets, containing the <code>alt</code>
+attribute text for the image;</li>
+<li>followed by a set of parentheses, containing the URL or path to
+the image, and an optional <code>title</code> attribute enclosed in double
+or single quotes.</li>
+</ul>
+
+<p>Reference-style image syntax looks like this:</p>
+
+<pre><code>![Alt text][id]
+</code></pre>
+
+<p>Where "id" is the name of a defined image reference. Image references
+are defined using syntax identical to link references:</p>
+
+<pre><code>[id]: url/to/image "Optional title attribute"
+</code></pre>
+
+<p>As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML <code><img></code> tags.</p>
+
+<hr>
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p>
+
+<pre><code><http://example.com/>
+</code></pre>
+
+<p>Markdown will turn this into:</p>
+
+<pre><code><a href="http://example.com/">http://example.com/</a>
+</code></pre>
+
+<p>Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:</p>
+
+<pre><code><address@example.com>
+</code></pre>
+
+<p>into something like this:</p>
+
+<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
+&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
+&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
+&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
+</code></pre>
+
+<p>which will render in a browser as a clickable link to "address@example.com".</p>
+
+<p>(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won't fool all of
+them. It's better than nothing, but an address published in this way
+will probably eventually start receiving spam.)</p>
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+<p>Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown's
+formatting syntax. For example, if you wanted to surround a word with
+literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes
+before the asterisks, like this:</p>
+
+<pre><code>\*literal asterisks\*
+</code></pre>
+
+<p>Markdown provides backslash escapes for the following characters:</p>
+
+<pre><code>\ backslash
+` backtick
+* asterisk
+_ underscore
+{} curly braces
+[] square brackets
+() parentheses
+# hash mark
++ plus sign
+- minus sign (hyphen)
+. dot
+! exclamation mark
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
new file mode 100644
index 0000000..57360a1
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text
@@ -0,0 +1,888 @@
+Markdown: Syntax
+================
+
+<ul id="ProjectSubmenu">
+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li>
+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li>
+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li>
+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li>
+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li>
+</ul>
+
+
+* [Overview](#overview)
+ * [Philosophy](#philosophy)
+ * [Inline HTML](#html)
+ * [Automatic Escaping for Special Characters](#autoescape)
+* [Block Elements](#block)
+ * [Paragraphs and Line Breaks](#p)
+ * [Headers](#header)
+ * [Blockquotes](#blockquote)
+ * [Lists](#list)
+ * [Code Blocks](#precode)
+ * [Horizontal Rules](#hr)
+* [Span Elements](#span)
+ * [Links](#link)
+ * [Emphasis](#em)
+ * [Code](#code)
+ * [Images](#img)
+* [Miscellaneous](#misc)
+ * [Backslash Escapes](#backslash)
+ * [Automatic Links](#autolink)
+
+
+**Note:** This document is itself written using Markdown; you
+can [see the source for it by adding '.text' to the URL][src].
+
+ [src]: /projects/markdown/syntax.text
+
+* * *
+
+<h2 id="overview">Overview</h2>
+
+<h3 id="philosophy">Philosophy</h3>
+
+Markdown is intended to be as easy-to-read and easy-to-write as is feasible.
+
+Readability, however, is emphasized above all else. A Markdown-formatted
+document should be publishable as-is, as plain text, without looking
+like it's been marked up with tags or formatting instructions. While
+Markdown's syntax has been influenced by several existing text-to-HTML
+filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4],
+[Grutatext] [5], and [EtText] [6] -- the single biggest source of
+inspiration for Markdown's syntax is the format of plain text email.
+
+ [1]: http://docutils.sourceforge.net/mirror/setext.html
+ [2]: http://www.aaronsw.com/2002/atx/
+ [3]: http://textism.com/tools/textile/
+ [4]: http://docutils.sourceforge.net/rst.html
+ [5]: http://www.triptico.com/software/grutatxt.html
+ [6]: http://ettext.taint.org/doc/
+
+To this end, Markdown's syntax is comprised entirely of punctuation
+characters, which punctuation characters have been carefully chosen so
+as to look like what they mean. E.g., asterisks around a word actually
+look like \*emphasis\*. Markdown lists look like, well, lists. Even
+blockquotes look like quoted passages of text, assuming you've ever
+used email.
+
+
+
+<h3 id="html">Inline HTML</h3>
+
+Markdown's syntax is intended for one purpose: to be used as a
+format for *writing* for the web.
+
+Markdown is not a replacement for HTML, or even close to it. Its
+syntax is very small, corresponding only to a very small subset of
+HTML tags. The idea is *not* to create a syntax that makes it easier
+to insert HTML tags. In my opinion, HTML tags are already easy to
+insert. The idea for Markdown is to make it easy to read, write, and
+edit prose. HTML is a *publishing* format; Markdown is a *writing*
+format. Thus, Markdown's formatting syntax only addresses issues that
+can be conveyed in plain text.
+
+For any markup that is not covered by Markdown's syntax, you simply
+use HTML itself. There's no need to preface it or delimit it to
+indicate that you're switching from Markdown to HTML; you just use
+the tags.
+
+The only restrictions are that block-level HTML elements -- e.g. `<div>`,
+`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding
+content by blank lines, and the start and end tags of the block should
+not be indented with tabs or spaces. Markdown is smart enough not
+to add extra (unwanted) `<p>` tags around HTML block-level tags.
+
+For example, to add an HTML table to a Markdown article:
+
+ This is a regular paragraph.
+
+ <table>
+ <tr>
+ <td>Foo</td>
+ </tr>
+ </table>
+
+ This is another regular paragraph.
+
+Note that Markdown formatting syntax is not processed within block-level
+HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an
+HTML block.
+
+Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be
+used anywhere in a Markdown paragraph, list item, or header. If you
+want, you can even use HTML tags instead of Markdown formatting; e.g. if
+you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's
+link or image syntax, go right ahead.
+
+Unlike block-level HTML tags, Markdown syntax *is* processed within
+span-level tags.
+
+
+<h3 id="autoescape">Automatic Escaping for Special Characters</h3>
+
+In HTML, there are two characters that demand special treatment: `<`
+and `&`. Left angle brackets are used to start tags; ampersands are
+used to denote HTML entities. If you want to use them as literal
+characters, you must escape them as entities, e.g. `<`, and
+`&`.
+
+Ampersands in particular are bedeviling for web writers. If you want to
+write about 'AT&T', you need to write '`AT&T`'. You even need to
+escape ampersands within URLs. Thus, if you want to link to:
+
+ http://images.google.com/images?num=30&q=larry+bird
+
+you need to encode the URL as:
+
+ http://images.google.com/images?num=30&q=larry+bird
+
+in your anchor tag `href` attribute. Needless to say, this is easy to
+forget, and is probably the single most common source of HTML validation
+errors in otherwise well-marked-up web sites.
+
+Markdown allows you to use these characters naturally, taking care of
+all the necessary escaping for you. If you use an ampersand as part of
+an HTML entity, it remains unchanged; otherwise it will be translated
+into `&`.
+
+So, if you want to include a copyright symbol in your article, you can write:
+
+ ©
+
+and Markdown will leave it alone. But if you write:
+
+ AT&T
+
+Markdown will translate it to:
+
+ AT&T
+
+Similarly, because Markdown supports [inline HTML](#html), if you use
+angle brackets as delimiters for HTML tags, Markdown will treat them as
+such. But if you write:
+
+ 4 < 5
+
+Markdown will translate it to:
+
+ 4 < 5
+
+However, inside Markdown code spans and blocks, angle brackets and
+ampersands are *always* encoded automatically. This makes it easy to use
+Markdown to write about HTML code. (As opposed to raw HTML, which is a
+terrible format for writing about HTML syntax, because every single `<`
+and `&` in your example code needs to be escaped.)
+
+
+* * *
+
+
+<h2 id="block">Block Elements</h2>
+
+
+<h3 id="p">Paragraphs and Line Breaks</h3>
+
+A paragraph is simply one or more consecutive lines of text, separated
+by one or more blank lines. (A blank line is any line that looks like a
+blank line -- a line containing nothing but spaces or tabs is considered
+blank.) Normal paragraphs should not be intended with spaces or tabs.
+
+The implication of the "one or more consecutive lines of text" rule is
+that Markdown supports "hard-wrapped" text paragraphs. This differs
+significantly from most other text-to-HTML formatters (including Movable
+Type's "Convert Line Breaks" option) which translate every line break
+character in a paragraph into a `<br />` tag.
+
+When you *do* want to insert a `<br />` break tag using Markdown, you
+end a line with two or more spaces, then type return.
+
+Yes, this takes a tad more effort to create a `<br />`, but a simplistic
+"every line break is a `<br />`" rule wouldn't work for Markdown.
+Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l]
+work best -- and look better -- when you format them with hard breaks.
+
+ [bq]: #blockquote
+ [l]: #list
+
+
+
+<h3 id="header">Headers</h3>
+
+Markdown supports two styles of headers, [Setext] [1] and [atx] [2].
+
+Setext-style headers are "underlined" using equal signs (for first-level
+headers) and dashes (for second-level headers). For example:
+
+ This is an H1
+ =============
+
+ This is an H2
+ -------------
+
+Any number of underlining `=`'s or `-`'s will work.
+
+Atx-style headers use 1-6 hash characters at the start of the line,
+corresponding to header levels 1-6. For example:
+
+ # This is an H1
+
+ ## This is an H2
+
+ ###### This is an H6
+
+Optionally, you may "close" atx-style headers. This is purely
+cosmetic -- you can use this if you think it looks better. The
+closing hashes don't even need to match the number of hashes
+used to open the header. (The number of opening hashes
+determines the header level.) :
+
+ # This is an H1 #
+
+ ## This is an H2 ##
+
+ ### This is an H3 ######
+
+
+<h3 id="blockquote">Blockquotes</h3>
+
+Markdown uses email-style `>` characters for blockquoting. If you're
+familiar with quoting passages of text in an email message, then you
+know how to create a blockquote in Markdown. It looks best if you hard
+wrap the text and put a `>` before every line:
+
+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+ > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+ > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+ >
+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+ > id sem consectetuer libero luctus adipiscing.
+
+Markdown allows you to be lazy and only put the `>` before the first
+line of a hard-wrapped paragraph:
+
+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
+ consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
+
+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
+ id sem consectetuer libero luctus adipiscing.
+
+Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by
+adding additional levels of `>`:
+
+ > This is the first level of quoting.
+ >
+ > > This is nested blockquote.
+ >
+ > Back to the first level.
+
+Blockquotes can contain other Markdown elements, including headers, lists,
+and code blocks:
+
+ > ## This is a header.
+ >
+ > 1. This is the first list item.
+ > 2. This is the second list item.
+ >
+ > Here's some example code:
+ >
+ > return shell_exec("echo $input | $markdown_script");
+
+Any decent text editor should make email-style quoting easy. For
+example, with BBEdit, you can make a selection and choose Increase
+Quote Level from the Text menu.
+
+
+<h3 id="list">Lists</h3>
+
+Markdown supports ordered (numbered) and unordered (bulleted) lists.
+
+Unordered lists use asterisks, pluses, and hyphens -- interchangably
+-- as list markers:
+
+ * Red
+ * Green
+ * Blue
+
+is equivalent to:
+
+ + Red
+ + Green
+ + Blue
+
+and:
+
+ - Red
+ - Green
+ - Blue
+
+Ordered lists use numbers followed by periods:
+
+ 1. Bird
+ 2. McHale
+ 3. Parish
+
+It's important to note that the actual numbers you use to mark the
+list have no effect on the HTML output Markdown produces. The HTML
+Markdown produces from the above list is:
+
+ <ol>
+ <li>Bird</li>
+ <li>McHale</li>
+ <li>Parish</li>
+ </ol>
+
+If you instead wrote the list in Markdown like this:
+
+ 1. Bird
+ 1. McHale
+ 1. Parish
+
+or even:
+
+ 3. Bird
+ 1. McHale
+ 8. Parish
+
+you'd get the exact same HTML output. The point is, if you want to,
+you can use ordinal numbers in your ordered Markdown lists, so that
+the numbers in your source match the numbers in your published HTML.
+But if you want to be lazy, you don't have to.
+
+If you do use lazy list numbering, however, you should still start the
+list with the number 1. At some point in the future, Markdown may support
+starting ordered lists at an arbitrary number.
+
+List markers typically start at the left margin, but may be indented by
+up to three spaces. List markers must be followed by one or more spaces
+or a tab.
+
+To make lists look nice, you can wrap items with hanging indents:
+
+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+But if you want to be lazy, you don't have to:
+
+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
+ viverra nec, fringilla in, laoreet vitae, risus.
+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
+ Suspendisse id sem consectetuer libero luctus adipiscing.
+
+If list items are separated by blank lines, Markdown will wrap the
+items in `<p>` tags in the HTML output. For example, this input:
+
+ * Bird
+ * Magic
+
+will turn into:
+
+ <ul>
+ <li>Bird</li>
+ <li>Magic</li>
+ </ul>
+
+But this:
+
+ * Bird
+
+ * Magic
+
+will turn into:
+
+ <ul>
+ <li><p>Bird</p></li>
+ <li><p>Magic</p></li>
+ </ul>
+
+List items may consist of multiple paragraphs. Each subsequent
+paragraph in a list item must be intended by either 4 spaces
+or one tab:
+
+ 1. This is a list item with two paragraphs. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit
+ mi posuere lectus.
+
+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet
+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
+ sit amet velit.
+
+ 2. Suspendisse id sem consectetuer libero luctus adipiscing.
+
+It looks nice if you indent every line of the subsequent
+paragraphs, but here again, Markdown will allow you to be
+lazy:
+
+ * This is a list item with two paragraphs.
+
+ This is the second paragraph in the list item. You're
+ only required to indent the first line. Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit.
+
+ * Another item in the same list.
+
+To put a blockquote within a list item, the blockquote's `>`
+delimiters need to be indented:
+
+ * A list item with a blockquote:
+
+ > This is a blockquote
+ > inside a list item.
+
+To put a code block within a list item, the code block needs
+to be indented *twice* -- 8 spaces or two tabs:
+
+ * A list item with a code block:
+
+ <code goes here>
+
+
+It's worth noting that it's possible to trigger an ordered list by
+accident, by writing something like this:
+
+ 1986. What a great season.
+
+In other words, a *number-period-space* sequence at the beginning of a
+line. To avoid this, you can backslash-escape the period:
+
+ 1986\. What a great season.
+
+
+
+<h3 id="precode">Code Blocks</h3>
+
+Pre-formatted code blocks are used for writing about programming or
+markup source code. Rather than forming normal paragraphs, the lines
+of a code block are interpreted literally. Markdown wraps a code block
+in both `<pre>` and `<code>` tags.
+
+To produce a code block in Markdown, simply indent every line of the
+block by at least 4 spaces or 1 tab. For example, given this input:
+
+ This is a normal paragraph:
+
+ This is a code block.
+
+Markdown will generate:
+
+ <p>This is a normal paragraph:</p>
+
+ <pre><code>This is a code block.
+ </code></pre>
+
+One level of indentation -- 4 spaces or 1 tab -- is removed from each
+line of the code block. For example, this:
+
+ Here is an example of AppleScript:
+
+ tell application "Foo"
+ beep
+ end tell
+
+will turn into:
+
+ <p>Here is an example of AppleScript:</p>
+
+ <pre><code>tell application "Foo"
+ beep
+ end tell
+ </code></pre>
+
+A code block continues until it reaches a line that is not indented
+(or the end of the article).
+
+Within a code block, ampersands (`&`) and angle brackets (`<` and `>`)
+are automatically converted into HTML entities. This makes it very
+easy to include example HTML source code using Markdown -- just paste
+it and indent it, and Markdown will handle the hassle of encoding the
+ampersands and angle brackets. For example, this:
+
+ <div class="footer">
+ © 2004 Foo Corporation
+ </div>
+
+will turn into:
+
+ <pre><code><div class="footer">
+ &copy; 2004 Foo Corporation
+ </div>
+ </code></pre>
+
+Regular Markdown syntax is not processed within code blocks. E.g.,
+asterisks are just literal asterisks within a code block. This means
+it's also easy to use Markdown to write about Markdown's own syntax.
+
+
+
+<h3 id="hr">Horizontal Rules</h3>
+
+You can produce a horizontal rule tag (`<hr />`) by placing three or
+more hyphens, asterisks, or underscores on a line by themselves. If you
+wish, you may use spaces between the hyphens or asterisks. Each of the
+following lines will produce a horizontal rule:
+
+ * * *
+
+ ***
+
+ *****
+
+ - - -
+
+ ---------------------------------------
+
+ _ _ _
+
+
+* * *
+
+<h2 id="span">Span Elements</h2>
+
+<h3 id="link">Links</h3>
+
+Markdown supports two style of links: *inline* and *reference*.
+
+In both styles, the link text is delimited by [square brackets].
+
+To create an inline link, use a set of regular parentheses immediately
+after the link text's closing square bracket. Inside the parentheses,
+put the URL where you want the link to point, along with an *optional*
+title for the link, surrounded in quotes. For example:
+
+ This is [an example](http://example.com/ "Title") inline link.
+
+ [This link](http://example.net/) has no title attribute.
+
+Will produce:
+
+ <p>This is <a href="http://example.com/" title="Title">
+ an example</a> inline link.</p>
+
+ <p><a href="http://example.net/">This link</a> has no
+ title attribute.</p>
+
+If you're referring to a local resource on the same server, you can
+use relative paths:
+
+ See my [About](/about/) page for details.
+
+Reference-style links use a second set of square brackets, inside
+which you place a label of your choosing to identify the link:
+
+ This is [an example][id] reference-style link.
+
+You can optionally use a space to separate the sets of brackets:
+
+ This is [an example] [id] reference-style link.
+
+Then, anywhere in the document, you define your link label like this,
+on a line by itself:
+
+ [id]: http://example.com/ "Optional Title Here"
+
+That is:
+
+* Square brackets containing the link identifier (optionally
+ indented from the left margin using up to three spaces);
+* followed by a colon;
+* followed by one or more spaces (or tabs);
+* followed by the URL for the link;
+* optionally followed by a title attribute for the link, enclosed
+ in double or single quotes.
+
+The link URL may, optionally, be surrounded by angle brackets:
+
+ [id]: <http://example.com/> "Optional Title Here"
+
+You can put the title attribute on the next line and use extra spaces
+or tabs for padding, which tends to look better with longer URLs:
+
+ [id]: http://example.com/longish/path/to/resource/here
+ "Optional Title Here"
+
+Link definitions are only used for creating links during Markdown
+processing, and are stripped from your document in the HTML output.
+
+Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links:
+
+ [link text][a]
+ [link text][A]
+
+are equivalent.
+
+The *implicit link name* shortcut allows you to omit the name of the
+link, in which case the link text itself is used as the name.
+Just use an empty set of square brackets -- e.g., to link the word
+"Google" to the google.com web site, you could simply write:
+
+ [Google][]
+
+And then define the link:
+
+ [Google]: http://google.com/
+
+Because link names may contain spaces, this shortcut even works for
+multiple words in the link text:
+
+ Visit [Daring Fireball][] for more information.
+
+And then define the link:
+
+ [Daring Fireball]: http://daringfireball.net/
+
+Link definitions can be placed anywhere in your Markdown document. I
+tend to put them immediately after each paragraph in which they're
+used, but if you want, you can put them all at the end of your
+document, sort of like footnotes.
+
+Here's an example of reference links in action:
+
+ I get 10 times more traffic from [Google] [1] than from
+ [Yahoo] [2] or [MSN] [3].
+
+ [1]: http://google.com/ "Google"
+ [2]: http://search.yahoo.com/ "Yahoo Search"
+ [3]: http://search.msn.com/ "MSN Search"
+
+Using the implicit link name shortcut, you could instead write:
+
+ I get 10 times more traffic from [Google][] than from
+ [Yahoo][] or [MSN][].
+
+ [google]: http://google.com/ "Google"
+ [yahoo]: http://search.yahoo.com/ "Yahoo Search"
+ [msn]: http://search.msn.com/ "MSN Search"
+
+Both of the above examples will produce the following HTML output:
+
+ <p>I get 10 times more traffic from <a href="http://google.com/"
+ title="Google">Google</a> than from
+ <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
+ or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
+
+For comparison, here is the same paragraph written using
+Markdown's inline link style:
+
+ I get 10 times more traffic from [Google](http://google.com/ "Google")
+ than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
+ [MSN](http://search.msn.com/ "MSN Search").
+
+The point of reference-style links is not that they're easier to
+write. The point is that with reference-style links, your document
+source is vastly more readable. Compare the above examples: using
+reference-style links, the paragraph itself is only 81 characters
+long; with inline-style links, it's 176 characters; and as raw HTML,
+it's 234 characters. In the raw HTML, there's more markup than there
+is text.
+
+With Markdown's reference-style links, a source document much more
+closely resembles the final output, as rendered in a browser. By
+allowing you to move the markup-related metadata out of the paragraph,
+you can add links without interrupting the narrative flow of your
+prose.
+
+
+<h3 id="em">Emphasis</h3>
+
+Markdown treats asterisks (`*`) and underscores (`_`) as indicators of
+emphasis. Text wrapped with one `*` or `_` will be wrapped with an
+HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML
+`<strong>` tag. E.g., this input:
+
+ *single asterisks*
+
+ _single underscores_
+
+ **double asterisks**
+
+ __double underscores__
+
+will produce:
+
+ <em>single asterisks</em>
+
+ <em>single underscores</em>
+
+ <strong>double asterisks</strong>
+
+ <strong>double underscores</strong>
+
+You can use whichever style you prefer; the lone restriction is that
+the same character must be used to open and close an emphasis span.
+
+Emphasis can be used in the middle of a word:
+
+ un*fucking*believable
+
+But if you surround an `*` or `_` with spaces, it'll be treated as a
+literal asterisk or underscore.
+
+To produce a literal asterisk or underscore at a position where it
+would otherwise be used as an emphasis delimiter, you can backslash
+escape it:
+
+ \*this text is surrounded by literal asterisks\*
+
+
+
+<h3 id="code">Code</h3>
+
+To indicate a span of code, wrap it with backtick quotes (`` ` ``).
+Unlike a pre-formatted code block, a code span indicates code within a
+normal paragraph. For example:
+
+ Use the `printf()` function.
+
+will produce:
+
+ <p>Use the <code>printf()</code> function.</p>
+
+To include a literal backtick character within a code span, you can use
+multiple backticks as the opening and closing delimiters:
+
+ ``There is a literal backtick (`) here.``
+
+which will produce this:
+
+ <p><code>There is a literal backtick (`) here.</code></p>
+
+The backtick delimiters surrounding a code span may include spaces --
+one after the opening, one before the closing. This allows you to place
+literal backtick characters at the beginning or end of a code span:
+
+ A single backtick in a code span: `` ` ``
+
+ A backtick-delimited string in a code span: `` `foo` ``
+
+will produce:
+
+ <p>A single backtick in a code span: <code>`</code></p>
+
+ <p>A backtick-delimited string in a code span: <code>`foo`</code></p>
+
+With a code span, ampersands and angle brackets are encoded as HTML
+entities automatically, which makes it easy to include example HTML
+tags. Markdown will turn this:
+
+ Please don't use any `<blink>` tags.
+
+into:
+
+ <p>Please don't use any <code><blink></code> tags.</p>
+
+You can write this:
+
+ `—` is the decimal-encoded equivalent of `—`.
+
+to produce:
+
+ <p><code>&#8212;</code> is the decimal-encoded
+ equivalent of <code>&mdash;</code>.</p>
+
+
+
+<h3 id="img">Images</h3>
+
+Admittedly, it's fairly difficult to devise a "natural" syntax for
+placing images into a plain text document format.
+
+Markdown uses an image syntax that is intended to resemble the syntax
+for links, allowing for two styles: *inline* and *reference*.
+
+Inline image syntax looks like this:
+
+ ![Alt text](/path/to/img.jpg)
+
+ ![Alt text](/path/to/img.jpg "Optional title")
+
+That is:
+
+* An exclamation mark: `!`;
+* followed by a set of square brackets, containing the `alt`
+ attribute text for the image;
+* followed by a set of parentheses, containing the URL or path to
+ the image, and an optional `title` attribute enclosed in double
+ or single quotes.
+
+Reference-style image syntax looks like this:
+
+ ![Alt text][id]
+
+Where "id" is the name of a defined image reference. Image references
+are defined using syntax identical to link references:
+
+ [id]: url/to/image "Optional title attribute"
+
+As of this writing, Markdown has no syntax for specifying the
+dimensions of an image; if this is important to you, you can simply
+use regular HTML `<img>` tags.
+
+
+* * *
+
+
+<h2 id="misc">Miscellaneous</h2>
+
+<h3 id="autolink">Automatic Links</h3>
+
+Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:
+
+ <http://example.com/>
+
+Markdown will turn this into:
+
+ <a href="http://example.com/">http://example.com/</a>
+
+Automatic links for email addresses work similarly, except that
+Markdown will also perform a bit of randomized decimal and hex
+entity-encoding to help obscure your address from address-harvesting
+spambots. For example, Markdown will turn this:
+
+ <address@example.com>
+
+into something like this:
+
+ <a href="mailto:addre
+ ss@example.co
+ m">address@exa
+ mple.com</a>
+
+which will render in a browser as a clickable link to "address@example.com".
+
+(This sort of entity-encoding trick will indeed fool many, if not
+most, address-harvesting bots, but it definitely won't fool all of
+them. It's better than nothing, but an address published in this way
+will probably eventually start receiving spam.)
+
+
+
+<h3 id="backslash">Backslash Escapes</h3>
+
+Markdown allows you to use backslash escapes to generate literal
+characters which would otherwise have special meaning in Markdown's
+formatting syntax. For example, if you wanted to surround a word with
+literal asterisks (instead of an HTML `<em>` tag), you can backslashes
+before the asterisks, like this:
+
+ \*literal asterisks\*
+
+Markdown provides backslash escapes for the following characters:
+
+ \ backslash
+ ` backtick
+ * asterisk
+ _ underscore
+ {} curly braces
+ [] square brackets
+ () parentheses
+ # hash mark
+ + plus sign
+ - minus sign (hyphen)
+ . dot
+ ! exclamation mark
+
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html
new file mode 100644
index 0000000..538bb4f
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html
@@ -0,0 +1,9 @@
+<blockquote>
+<p>foo</p>
+
+<blockquote>
+<p>bar</p>
+</blockquote>
+
+<p>foo</p>
+</blockquote>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text
new file mode 100644
index 0000000..ed3c624
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text
@@ -0,0 +1,5 @@
+> foo
+>
+> > bar
+>
+> foo
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
new file mode 100644
index 0000000..d6fa427
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html
@@ -0,0 +1,166 @@
+<h2>Unordered</h2>
+
+<p>Asterisks tight:</p>
+
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+
+<p>Asterisks loose:</p>
+
+<ul>
+<li><p>asterisk 1</p></li>
+
+<li><p>asterisk 2</p></li>
+
+<li><p>asterisk 3</p></li>
+</ul>
+
+<hr>
+
+<p>Pluses tight:</p>
+
+<ul>
+<li>Plus 1</li>
+<li>Plus 2</li>
+<li>Plus 3</li>
+</ul>
+
+<p>Pluses loose:</p>
+
+<ul>
+<li><p>Plus 1</p></li>
+
+<li><p>Plus 2</p></li>
+
+<li><p>Plus 3</p></li>
+</ul>
+
+<hr>
+
+<p>Minuses tight:</p>
+
+<ul>
+<li>Minus 1</li>
+<li>Minus 2</li>
+<li>Minus 3</li>
+</ul>
+
+<p>Minuses loose:</p>
+
+<ul>
+<li><p>Minus 1</p></li>
+
+<li><p>Minus 2</p></li>
+
+<li><p>Minus 3</p></li>
+</ul>
+
+<h2>Ordered</h2>
+
+<p>Tight:</p>
+
+<ol>
+<li>First</li>
+<li>Second</li>
+<li>Third</li>
+</ol>
+
+<p>and:</p>
+
+<ol>
+<li>One</li>
+<li>Two</li>
+<li>Three</li>
+</ol>
+
+<p>Loose using tabs:</p>
+
+<ol>
+<li><p>First</p></li>
+
+<li><p>Second</p></li>
+
+<li><p>Third</p></li>
+</ol>
+
+<p>and using spaces:</p>
+
+<ol>
+<li><p>One</p></li>
+
+<li><p>Two</p></li>
+
+<li><p>Three</p></li>
+</ol>
+
+<p>Multiple paragraphs:</p>
+
+<ol>
+<li><p>Item 1, graf one.</p>
+
+<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's
+back.</p></li>
+
+<li><p>Item 2.</p></li>
+
+<li><p>Item 3.</p></li>
+</ol>
+
+<h2>Nested</h2>
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab
+
+<ul>
+<li>Tab</li>
+</ul></li>
+</ul></li>
+</ul>
+
+<p>Here's another:</p>
+
+<ol>
+<li>First</li>
+<li>Second:
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+<li>Third</li>
+</ol>
+
+<p>Same thing but with paragraphs:</p>
+
+<ol>
+<li><p>First</p></li>
+
+<li><p>Second:</p>
+
+<ul>
+<li>Fee</li>
+<li>Fie</li>
+<li>Foe</li>
+</ul></li>
+
+<li><p>Third</p></li>
+</ol>
+
+<p>This was an error in Markdown 1.0.1:</p>
+
+<ul>
+<li><p>this</p>
+
+<ul>
+<li>sub</li>
+</ul>
+
+<p>that</p></li>
+</ul>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
new file mode 100644
index 0000000..7f3b497
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text
@@ -0,0 +1,131 @@
+## Unordered
+
+Asterisks tight:
+
+* asterisk 1
+* asterisk 2
+* asterisk 3
+
+
+Asterisks loose:
+
+* asterisk 1
+
+* asterisk 2
+
+* asterisk 3
+
+* * *
+
+Pluses tight:
+
++ Plus 1
++ Plus 2
++ Plus 3
+
+
+Pluses loose:
+
++ Plus 1
+
++ Plus 2
+
++ Plus 3
+
+* * *
+
+
+Minuses tight:
+
+- Minus 1
+- Minus 2
+- Minus 3
+
+
+Minuses loose:
+
+- Minus 1
+
+- Minus 2
+
+- Minus 3
+
+
+## Ordered
+
+Tight:
+
+1. First
+2. Second
+3. Third
+
+and:
+
+1. One
+2. Two
+3. Three
+
+
+Loose using tabs:
+
+1. First
+
+2. Second
+
+3. Third
+
+and using spaces:
+
+1. One
+
+2. Two
+
+3. Three
+
+Multiple paragraphs:
+
+1. Item 1, graf one.
+
+ Item 2. graf two. The quick brown fox jumped over the lazy dog's
+ back.
+
+2. Item 2.
+
+3. Item 3.
+
+
+
+## Nested
+
+* Tab
+ * Tab
+ * Tab
+
+Here's another:
+
+1. First
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+3. Third
+
+Same thing but with paragraphs:
+
+1. First
+
+2. Second:
+ * Fee
+ * Fie
+ * Foe
+
+3. Third
+
+
+This was an error in Markdown 1.0.1:
+
+* this
+
+ * sub
+
+ that
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html
new file mode 100644
index 0000000..71ec78c
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html
@@ -0,0 +1,7 @@
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
+
+<p><strong><em>This is strong and em.</em></strong></p>
+
+<p>So is <strong><em>this</em></strong> word.</p>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text
new file mode 100644
index 0000000..95ee690
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text
@@ -0,0 +1,7 @@
+***This is strong and em.***
+
+So is ***this*** word.
+
+___This is strong and em.___
+
+So is ___this___ word.
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html
new file mode 100644
index 0000000..64006d9
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html
@@ -0,0 +1,26 @@
+<ul>
+<li><p>this is a list item
+indented with tabs</p></li>
+
+<li><p>this is a list item
+indented with spaces</p></li>
+</ul>
+
+<p>Code:</p>
+
+<pre><code>this code block is indented by one tab
+</code></pre>
+
+<p>And:</p>
+
+<pre><code> this code block is indented by two tabs
+</code></pre>
+
+<p>And:</p>
+
+<pre><code>+ this is an example list item
+ indented with tabs
+
++ this is an example list item
+ indented with spaces
+</code></pre>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text
new file mode 100644
index 0000000..589d113
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text
@@ -0,0 +1,21 @@
++ this is a list item
+ indented with tabs
+
++ this is a list item
+ indented with spaces
+
+Code:
+
+ this code block is indented by one tab
+
+And:
+
+ this code block is indented by two tabs
+
+And:
+
+ + this is an example list item
+ indented with tabs
+
+ + this is an example list item
+ indented with spaces
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html
new file mode 100644
index 0000000..9c45b69
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html
@@ -0,0 +1,9 @@
+<blockquote>
+<p>A list within a blockquote:</p>
+
+<ul>
+<li>asterisk 1</li>
+<li>asterisk 2</li>
+<li>asterisk 3</li>
+</ul>
+</blockquote>
diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text
new file mode 100644
index 0000000..5f18b8d
--- /dev/null
+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text
@@ -0,0 +1,5 @@
+> A list within a blockquote:
+>
+> * asterisk 1
+> * asterisk 2
+> * asterisk 3
diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml b/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml
new file mode 100644
index 0000000..aaee9cf
--- /dev/null
+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+ - 1.4
+install:
+ - go get golang.org/x/tools/cmd/vet
+script:
+ - go get -t -v ./...
+ - diff -u <(echo -n) <(gofmt -d ./)
+ - go tool vet ./
+ - go test -v -race ./...
diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md b/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md
new file mode 100644
index 0000000..089c440
--- /dev/null
+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md
@@ -0,0 +1,25 @@
+sanitized_anchor_name [![Build Status](https://travis-ci.org/shurcooL/sanitized_anchor_name.svg?branch=master)](https://travis-ci.org/shurcooL/sanitized_anchor_name)
+=====================
+
+Package `sanitized_anchor_name` provides a func to create sanitized anchor names.
+
+Its logic can be reused by multiple packages to create interoperable anchor names and links to those anchors.
+
+At this time, it does not try to ensure that generated anchor names are unique, that responsibility falls on the caller.
+
+Example
+=======
+
+```Go
+anchorName := sanitized_anchor_name.Create("This is a header")
+
+fmt.Println(anchorName)
+
+// Output:
+// this-is-a-header
+```
+
+License
+-------
+
+- [MIT License](http://opensource.org/licenses/mit-license.php)
diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go
new file mode 100644
index 0000000..72a8753
--- /dev/null
+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go
@@ -0,0 +1,29 @@
+// Package sanitized_anchor_name provides a func to create sanitized anchor names.
+//
+// Its logic can be reused by multiple packages to create interoperable anchor names
+// and links to those anchors.
+//
+// At this time, it does not try to ensure that generated anchor names
+// are unique, that responsibility falls on the caller.
+package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name"
+
+import "unicode"
+
+// Create returns a sanitized anchor name for the given text.
+func Create(text string) string {
+ var anchorName []rune
+ var futureDash = false
+ for _, r := range []rune(text) {
+ switch {
+ case unicode.IsLetter(r) || unicode.IsNumber(r):
+ if futureDash && len(anchorName) > 0 {
+ anchorName = append(anchorName, '-')
+ }
+ futureDash = false
+ anchorName = append(anchorName, unicode.ToLower(r))
+ default:
+ futureDash = true
+ }
+ }
+ return string(anchorName)
+}
diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go
new file mode 100644
index 0000000..ad03201
--- /dev/null
+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go
@@ -0,0 +1,35 @@
+package sanitized_anchor_name_test
+
+import (
+ "fmt"
+
+ "github.com/shurcooL/sanitized_anchor_name"
+)
+
+func ExampleCreate() {
+ anchorName := sanitized_anchor_name.Create("This is a header")
+
+ fmt.Println(anchorName)
+
+ // Output:
+ // this-is-a-header
+}
+
+func ExampleCreate2() {
+ fmt.Println(sanitized_anchor_name.Create("This is a header"))
+ fmt.Println(sanitized_anchor_name.Create("This is also a header"))
+ fmt.Println(sanitized_anchor_name.Create("main.go"))
+ fmt.Println(sanitized_anchor_name.Create("Article 123"))
+ fmt.Println(sanitized_anchor_name.Create("<- Let's try this, shall we?"))
+ fmt.Printf("%q\n", sanitized_anchor_name.Create(" "))
+ fmt.Println(sanitized_anchor_name.Create("Hello, 世界"))
+
+ // Output:
+ // this-is-a-header
+ // this-is-also-a-header
+ // main-go
+ // article-123
+ // let-s-try-this-shall-we
+ // ""
+ // hello-世界
+}
--
1.8.3.1