diff --git a/.docker.metadata b/.docker.metadata index d90ff1c..cd01820 100644 --- a/.docker.metadata +++ b/.docker.metadata @@ -1,3 +1,2 @@ 71c867c07de3e8649a69b96d8b8b3402606208fe SOURCES/codegansta.tgz -c401b4a3a1b847713e2fbbebbf68fe56a7706b67 SOURCES/docker-2a2f26c.tar.gz -4a2408e3e452c09c9e41844d53257c51eb0080d4 SOURCES/docker-man-3.tar.gz +56f5602688496486e3b753da762fc0bb97c34c7c SOURCES/v1.3.2.tar.gz diff --git a/.gitignore b/.gitignore index 29ac623..2afe20b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ SOURCES/codegansta.tgz -SOURCES/docker-2a2f26c.tar.gz -SOURCES/docker-man-3.tar.gz +SOURCES/v1.3.2.tar.gz diff --git a/README.debrand b/README.debrand deleted file mode 100644 index 01c46d2..0000000 --- a/README.debrand +++ /dev/null @@ -1,2 +0,0 @@ -Warning: This package was configured for automatic debranding, but the changes -failed to apply. diff --git a/SOURCES/0001-On-Red-Hat-Registry-Servers-we-return-404-on-certifi.patch b/SOURCES/0001-On-Red-Hat-Registry-Servers-we-return-404-on-certifi.patch deleted file mode 100644 index c621351..0000000 --- a/SOURCES/0001-On-Red-Hat-Registry-Servers-we-return-404-on-certifi.patch +++ /dev/null @@ -1,34 +0,0 @@ -diff -up docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/docs/sources/articles/certificates.md.404 docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/docs/sources/articles/certificates.md ---- docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/docs/sources/articles/certificates.md.404 2014-09-22 10:40:10.000000000 -0400 -+++ docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/docs/sources/articles/certificates.md 2014-10-20 13:23:56.827130505 -0400 -@@ -31,7 +31,7 @@ repository. - - > **Note:** - > If there are multiple certificates, each will be tried in alphabetical --> order. If there is an authentication error (e.g., 403, 5xx, etc.), Docker -+> order. If there is an authentication error (e.g., 403, 404, 5xx, etc.), Docker - > will continue to try with the next certificate. - - Our example is set up like this: -diff -up docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go.404 docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go ---- docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go.404 2014-10-20 13:23:56.828130500 -0400 -+++ docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go 2014-10-20 13:26:00.736574647 -0400 -@@ -168,14 +168,11 @@ func doRequest(req *http.Request, jar ht - for i, cert := range certs { - client := newClient(jar, pool, cert, timeout) - res, err := client.Do(req) -- if i == len(certs)-1 { -- // If this is the last cert, always return the result -+ if i == len(certs)-1 || err == nil && -+ res.StatusCode != 403 && -+ res.StatusCode != 404 && -+ res.StatusCode < 500 { - return res, client, err -- } else { -- // Otherwise, continue to next cert if 403 or 5xx -- if err == nil && res.StatusCode != 403 && !(res.StatusCode >= 500 && res.StatusCode < 600) { -- return res, client, err -- } - } - } - } diff --git a/SOURCES/0007-validate-image-ID-properly-before-load.patch b/SOURCES/0007-validate-image-ID-properly-before-load.patch new file mode 100644 index 0000000..22a23cc --- /dev/null +++ b/SOURCES/0007-validate-image-ID-properly-before-load.patch @@ -0,0 +1,104 @@ +From 4dea7eefc1a7ff0083bf47cda22247067488ace0 Mon Sep 17 00:00:00 2001 +From: unclejack <unclejacksons@gmail.com> +Date: Thu, 27 Nov 2014 23:55:03 +0200 +Subject: [PATCH 7/9] validate image ID properly & before load + +Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> +--- + graph/load.go | 5 +++++ + graph/tags_unit_test.go | 2 +- + registry/registry.go | 4 ++-- + utils/utils.go | 12 +++++++----- + 4 files changed, 15 insertions(+), 8 deletions(-) + +diff --git a/graph/load.go b/graph/load.go +index fcbeef6..f27aca4 100644 +--- a/graph/load.go ++++ b/graph/load.go +@@ -12,6 +12,7 @@ import ( + "github.com/docker/docker/pkg/archive" + "github.com/docker/docker/pkg/chrootarchive" + "github.com/docker/docker/pkg/log" ++ "github.com/docker/docker/utils" + ) + + // Loads a set of images into the repository. This is the complementary of ImageExport. +@@ -112,6 +113,10 @@ func (s *TagStore) recursiveLoad(eng *engine.Engine, address, tmpImageDir string + log.Debugf("Error unmarshalling json", err) + return err + } ++ if err := utils.ValidateID(img.ID); err != nil { ++ log.Debugf("Error validating ID: %s", err) ++ return err ++ } + if img.Parent != "" { + if !s.graph.Exists(img.Parent) { + if err := s.recursiveLoad(eng, img.Parent, tmpImageDir); err != nil { +diff --git a/graph/tags_unit_test.go b/graph/tags_unit_test.go +index da51254..bf94deb 100644 +--- a/graph/tags_unit_test.go ++++ b/graph/tags_unit_test.go +@@ -16,7 +16,7 @@ import ( + + const ( + testImageName = "myapp" +- testImageID = "foo" ++ testImageID = "1a2d3c4d4e5fa2d2a21acea242a5e2345d3aefc3e7dfa2a2a2a21a2a2ad2d234" + ) + + func fakeTar() (io.Reader, error) { +diff --git a/registry/registry.go b/registry/registry.go +index a03790a..e0285a2 100644 +--- a/registry/registry.go ++++ b/registry/registry.go +@@ -23,7 +23,6 @@ var ( + ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")") + ErrDoesNotExist = errors.New("Image does not exist") + errLoginRequired = errors.New("Authentication is required.") +- validHex = regexp.MustCompile(`^([a-f0-9]{64})$`) + validNamespace = regexp.MustCompile(`^([a-z0-9_]{4,30})$`) + validRepo = regexp.MustCompile(`^([a-z0-9-_.]+)$`) + ) +@@ -177,7 +176,8 @@ func validateRepositoryName(repositoryName string) error { + namespace = "library" + name = nameParts[0] + +- if validHex.MatchString(name) { ++ // the repository name must not be a valid image ID ++ if err := utils.ValidateID(name); err == nil { + return fmt.Errorf("Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", name) + } + } else { +diff --git a/utils/utils.go b/utils/utils.go +index 792b80b..4c65f13 100644 +--- a/utils/utils.go ++++ b/utils/utils.go +@@ -31,6 +31,10 @@ type KeyValuePair struct { + Value string + } + ++var ( ++ validHex = regexp.MustCompile(`^([a-f0-9]{64})$`) ++) ++ + // Request a given URL and return an io.Reader + func Download(url string) (resp *http.Response, err error) { + if resp, err = http.Get(url); err != nil { +@@ -190,11 +194,9 @@ func GenerateRandomID() string { + } + + func ValidateID(id string) error { +- if id == "" { +- return fmt.Errorf("Id can't be empty") +- } +- if strings.Contains(id, ":") { +- return fmt.Errorf("Invalid character in id: ':'") ++ if ok := validHex.MatchString(id); !ok { ++ err := fmt.Errorf("image ID '%s' is invalid", id) ++ return err + } + return nil + } +-- +1.9.3 (Apple Git-50) + diff --git a/SOURCES/docker-reverse-entitlement.patch b/SOURCES/docker-reverse-entitlement.patch deleted file mode 100644 index ffdc5f5..0000000 --- a/SOURCES/docker-reverse-entitlement.patch +++ /dev/null @@ -1,50 +0,0 @@ -diff -up docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go.entitlement docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go ---- docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go.entitlement 2014-10-30 12:47:19.638087268 -0400 -+++ docker-2a2f26c1979cdaed884c765ea3dd203543e7e284/registry/registry.go 2014-10-30 12:48:30.778233169 -0400 -@@ -91,12 +91,6 @@ func doRequest(req *http.Request, jar ht - if err != nil && !os.IsNotExist(err) { - return nil, nil, err - } -- hostDir = path.Join(" /etc/pki/entitlement", req.URL.Host) -- if fs1, err := ioutil.ReadDir(hostDir); err == nil { -- for _, f := range fs1 { -- fs = append(fs, f) -- } -- } - - var ( - pool *x509.CertPool -@@ -124,33 +118,6 @@ func doRequest(req *http.Request, jar ht - cert, err := tls.LoadX509KeyPair(path.Join(hostDir, certName), path.Join(hostDir, keyName)) - if err != nil { - return nil, nil, err -- } -- certs = append(certs, &cert) -- } -- } -- if strings.HasSuffix(f.Name(), ".key") { -- keyName := f.Name() -- certName := keyName[:len(keyName)-4] + ".cert" -- if !hasFile(fs, certName) { -- return nil, nil, fmt.Errorf("Missing certificate %s for key %s", certName, keyName) -- } -- } -- if strings.HasSuffix(f.Name(), ".pem") { -- if strings.HasSuffix(f.Name(), "-key.pem") { -- keyName := f.Name() -- certName := keyName[:len(keyName)-len("-key.pem")] + ".pem" -- if !hasFile(fs, certName) { -- return nil, nil, fmt.Errorf("Missing certificate %s for key %s", certName, keyName) -- } -- } else { -- certName := f.Name() -- keyName := certName[:len(certName)-len(".pem")] + "-key.pem" -- if !hasFile(fs, keyName) { -- return nil, nil, fmt.Errorf("Missing key %s for certificate %s", keyName, certName) -- } -- cert, err := tls.LoadX509KeyPair(path.Join(hostDir, certName), path.Join(hostDir, keyName)) -- if err != nil { -- return nil, nil, err - } - certs = append(certs, &cert) - } diff --git a/SOURCES/docker.service b/SOURCES/docker.service index 5ed3e23..469bdb4 100644 --- a/SOURCES/docker.service +++ b/SOURCES/docker.service @@ -1,7 +1,7 @@ [Unit] Description=Docker Application Container Engine -Documentation=http://docs.docker.io -After=network.target +Documentation=http://docs.docker.com +After=network.target docker.socket Requires=docker.socket [Service] @@ -9,10 +9,9 @@ Type=notify EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage ExecStart=/usr/bin/docker -d $OPTIONS $DOCKER_STORAGE_OPTIONS -Restart=on-failure LimitNOFILE=1048576 LimitNPROC=1048576 +MountFlags=private [Install] -Also=docker.socket WantedBy=multi-user.target diff --git a/SOURCES/docker.socket b/SOURCES/docker.socket deleted file mode 100644 index 7dd9509..0000000 --- a/SOURCES/docker.socket +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=Docker Socket for the API -PartOf=docker.service - -[Socket] -ListenStream=/var/run/docker.sock -SocketMode=0660 -SocketUser=root -SocketGroup=docker - -[Install] -WantedBy=sockets.target diff --git a/SOURCES/docker.sysconfig b/SOURCES/docker.sysconfig index 0b63c43..1613870 100644 --- a/SOURCES/docker.sysconfig +++ b/SOURCES/docker.sysconfig @@ -1,4 +1,9 @@ # /etc/sysconfig/docker # Modify these options if you want to change the way the docker daemon runs -OPTIONS=--selinux-enabled +OPTIONS=--selinux-enabled -H fd:// + +# Location used for temporary files, such as those created by +# docker load and build operations. Default is /var/lib/docker/tmp +# Can be overriden by setting the following environment variable. +# DOCKER_TMPDIR=/var/tmp diff --git a/SOURCES/go-md2man.patch b/SOURCES/go-md2man.patch new file mode 100644 index 0000000..c6cb17b --- /dev/null +++ b/SOURCES/go-md2man.patch @@ -0,0 +1,12077 @@ +From 626f83f8fff1c8ec87c96ec283a3cf2f99978d39 Mon Sep 17 00:00:00 2001 +From: Lokesh Mandvekar <lsm5@fedoraproject.org> +Date: Thu, 13 Nov 2014 11:24:09 -0800 +Subject: [PATCH] include vendor repos for manpage gen + +Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> +--- + vendor/src/github.com/cpuguy83/go-md2man/README.md | 12 + + .../github.com/cpuguy83/go-md2man/mangen/mangen.go | 269 ++++ + vendor/src/github.com/cpuguy83/go-md2man/md2man.go | 55 + + .../src/github.com/russross/blackfriday/.gitignore | 8 + + .../src/github.com/russross/blackfriday/README.md | 255 ++++ + .../src/github.com/russross/blackfriday/block.go | 1315 ++++++++++++++++++++ + .../github.com/russross/blackfriday/block_test.go | 1063 ++++++++++++++++ + vendor/src/github.com/russross/blackfriday/html.go | 899 +++++++++++++ + .../src/github.com/russross/blackfriday/inline.go | 1078 ++++++++++++++++ + .../github.com/russross/blackfriday/inline_test.go | 796 ++++++++++++ + .../src/github.com/russross/blackfriday/latex.go | 332 +++++ + .../github.com/russross/blackfriday/markdown.go | 845 +++++++++++++ + .../github.com/russross/blackfriday/sanitize.go | 154 +++ + .../russross/blackfriday/sanitize_test.go | 199 +++ + .../github.com/russross/blackfriday/smartypants.go | 376 ++++++ + .../upskirtref/Amps and angle encoding.html | 17 + + .../upskirtref/Amps and angle encoding.text | 21 + + .../blackfriday/upskirtref/Auto links.html | 18 + + .../blackfriday/upskirtref/Auto links.text | 13 + + .../blackfriday/upskirtref/Backslash escapes.html | 123 ++ + .../blackfriday/upskirtref/Backslash escapes.text | 126 ++ + .../upskirtref/Blockquotes with code blocks.html | 15 + + .../upskirtref/Blockquotes with code blocks.text | 11 + + .../blackfriday/upskirtref/Code Blocks.html | 18 + + .../blackfriday/upskirtref/Code Blocks.text | 14 + + .../blackfriday/upskirtref/Code Spans.html | 5 + + .../blackfriday/upskirtref/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/upskirtref/Horizontal rules.html | 71 ++ + .../blackfriday/upskirtref/Horizontal rules.text | 67 + + .../upskirtref/Inline HTML (Advanced).html | 15 + + .../upskirtref/Inline HTML (Advanced).text | 15 + + .../upskirtref/Inline HTML (Simple).html | 72 ++ + .../upskirtref/Inline HTML (Simple).text | 69 + + .../upskirtref/Inline HTML comments.html | 13 + + .../upskirtref/Inline HTML comments.text | 13 + + .../upskirtref/Links, inline style.html | 11 + + .../upskirtref/Links, inline style.text | 12 + + .../upskirtref/Links, reference style.html | 52 + + .../upskirtref/Links, reference style.text | 71 ++ + .../upskirtref/Links, shortcut references.html | 9 + + .../upskirtref/Links, shortcut references.text | 20 + + .../upskirtref/Literal quotes in titles.html | 3 + + .../upskirtref/Literal quotes in titles.text | 7 + + .../Markdown Documentation - Basics.html | 314 +++++ + .../Markdown Documentation - Basics.text | 306 +++++ + .../Markdown Documentation - Syntax.html | 946 ++++++++++++++ + .../Markdown Documentation - Syntax.text | 888 +++++++++++++ + .../blackfriday/upskirtref/Nested blockquotes.html | 9 + + .../blackfriday/upskirtref/Nested blockquotes.text | 5 + + .../upskirtref/Ordered and unordered lists.html | 166 +++ + .../upskirtref/Ordered and unordered lists.text | 131 ++ + .../upskirtref/Strong and em together.html | 7 + + .../upskirtref/Strong and em together.text | 7 + + .../russross/blackfriday/upskirtref/Tabs.html | 26 + + .../russross/blackfriday/upskirtref/Tabs.text | 21 + + .../russross/blackfriday/upskirtref/Tidyness.html | 9 + + .../russross/blackfriday/upskirtref/Tidyness.text | 5 + + .../russross/blackfriday/upskirtref_test.go | 128 ++ + 62 files changed, 11569 insertions(+) + create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/README.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/.gitignore + 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/sanitize.go + create mode 100644 vendor/src/github.com/russross/blackfriday/sanitize_test.go + create mode 100644 vendor/src/github.com/russross/blackfriday/smartypants.go + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Amps and angle encoding.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Amps and angle encoding.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Auto links.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Auto links.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Backslash escapes.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Backslash escapes.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Blockquotes with code blocks.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Blockquotes with code blocks.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Code Blocks.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Code Blocks.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Code Spans.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Code Spans.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines no empty line before block.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines no empty line before block.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Horizontal rules.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Horizontal rules.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Advanced).html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Advanced).text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Simple).html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Simple).text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML comments.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML comments.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, inline style.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, inline style.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, reference style.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, reference style.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, shortcut references.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Links, shortcut references.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Literal quotes in titles.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Literal quotes in titles.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Basics.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Basics.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Syntax.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Syntax.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Nested blockquotes.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Nested blockquotes.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Ordered and unordered lists.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Ordered and unordered lists.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Strong and em together.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Strong and em together.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Tabs.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Tabs.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Tidyness.html + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref/Tidyness.text + create mode 100644 vendor/src/github.com/russross/blackfriday/upskirtref_test.go + +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..58e36e9 +--- /dev/null ++++ b/vendor/src/github.com/cpuguy83/go-md2man/README.md +@@ -0,0 +1,12 @@ ++go-md2man ++========= ++ ++** Work in Progress ** ++This still needs a lot of help to be complete, or even usable! ++ ++Uses blackfirday to process markdown ++ ++### Usage ++ ++./md2man -in /path/to/markdownfile.md -out /manfile/output/path ++ +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..eb24957 +--- /dev/null ++++ b/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go +@@ -0,0 +1,269 @@ ++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") ++} ++ ++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) { ++ // a pretty lame thing to do... ++ 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 level { ++ case 1: ++ out.WriteString("\n.SH ") ++ case 2: ++ out.WriteString(".SH ") ++ default: ++ out.WriteString(".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) { ++ fmt.Errorf("man: Raw HTML not supported") ++} ++ ++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/.gitignore b/vendor/src/github.com/russross/blackfriday/.gitignore +new file mode 100644 +index 0000000..75623dc +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/.gitignore +@@ -0,0 +1,8 @@ ++*.out ++*.swp ++*.8 ++*.6 ++_obj ++_test* ++markdown ++tags +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..55270d8 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/README.md +@@ -0,0 +1,255 @@ ++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 [upskirt][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 import it into a ++project: ++ ++ import "github.com/russross/blackfriday" ++ ++and when you build that project with `go build`, blackfriday will be ++downloaded and installed automatically. ++ ++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) ++ ++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 upskirt 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*. It is ++ not bullet proof against JavaScript injections, though we're working ++ on it (https://github.com/russross/blackfriday/issues/11 tracks the ++ progress). ++ ++* **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 ++* Markdown pretty-printer output engine ++* 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: ++ ++> 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. ++ ++ ++ [1]: http://daringfireball.net/projects/markdown/ "Markdown" ++ [2]: http://golang.org/ "Go Language" ++ [3]: http://github.com/tanoku/upskirt "Upskirt" +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..d21a0e6 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/block.go +@@ -0,0 +1,1315 @@ ++// ++// 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" ++ ++// 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 { ++ 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 < 3 && data[i] == ' ' { ++ i++ ++ } ++ ++ // 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 data[i] == c { ++ size++ ++ i++ ++ } ++ ++ // 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 data[i] == ' ' { ++ i++ ++ } ++ ++ syntaxStart := i ++ ++ if data[i] == '{' { ++ i++ ++ syntaxStart++ ++ ++ for data[i] != '}' && data[i] != '\n' { ++ syn++ ++ i++ ++ } ++ ++ if 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 !isspace(data[i]) { ++ syn++ ++ i++ ++ } ++ } ++ ++ language := string(data[syntaxStart : syntaxStart+syn]) ++ *syntax = &language ++ } ++ ++ for data[i] == ' ' { ++ i++ ++ } ++ if 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 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]) ++ p.r.Header(out, work, level, "") ++ ++ // 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..c9d4a88 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/block_test.go +@@ -0,0 +1,1063 @@ ++// ++// 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 runMarkdownBlock(input string, extensions int) string { ++ htmlFlags := 0 ++ htmlFlags |= HTML_USE_XHTML ++ ++ renderer := HtmlRenderer(htmlFlags, "", "") ++ ++ return string(Markdown([]byte(input), renderer, extensions)) ++} ++ ++func doTestsBlock(t *testing.T, tests []string, extensions int) { ++ // 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 := runMarkdownBlock(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 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 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=\"go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n", ++ ++ "``` c\n/* special & char < > \" escaping */\n```\n", ++ "<pre><code class=\"c\">/* special & char < > " escaping */\n</code></pre>\n", ++ ++ "``` c\nno *inline* processing ~~of text~~\n```\n", ++ "<pre><code class=\"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=\"ocaml\">language in braces\n</code></pre>\n", ++ ++ "``` {ocaml} \nwith extra whitespace\n```\n", ++ "<pre><code class=\"ocaml\">with extra whitespace\n</code></pre>\n", ++ ++ "```{ ocaml }\nwith extra whitespace\n```\n", ++ "<pre><code class=\"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=\"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=\"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=\"oz\">leading spaces\n</code></pre>\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"oz\">leading spaces\n</code></pre>\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"oz\">leading spaces\n</code></pre>\n", ++ ++ "``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"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=\"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=\"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=\"oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Bla Bla</p>\n\n<pre><code class=\"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=\"oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Some text in between</p>\n\n<pre><code class=\"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=\"go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n", ++ ++ "``` c\n/* special & char < > \" escaping */\n```\n", ++ "<pre><code class=\"c\">/* special & char < > " escaping */\n</code></pre>\n", ++ ++ "``` c\nno *inline* processing ~~of text~~\n```\n", ++ "<pre><code class=\"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=\"ocaml\">language in braces\n</code></pre>\n", ++ ++ "``` {ocaml} \nwith extra whitespace\n```\n", ++ "<pre><code class=\"ocaml\">with extra whitespace\n</code></pre>\n", ++ ++ "```{ ocaml }\nwith extra whitespace\n```\n", ++ "<pre><code class=\"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=\"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=\"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=\"oz\">leading spaces\n</code></pre>\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"oz\">leading spaces\n</code></pre>\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"oz\">leading spaces\n</code></pre>\n", ++ ++ "``` oz\nleading spaces\n ```\n", ++ "<pre><code class=\"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..982131c +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/html.go +@@ -0,0 +1,899 @@ ++// ++// 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_SANITIZE_OUTPUT // strip output of everything that's not known to be safe ++ HTML_SAFELINK // only link to trusted protocols ++ HTML_NOFOLLOW_LINKS // only link with rel="nofollow" ++ 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_GITHUB_BLOCKCODE // use github fenced code rendering rules ++ 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_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 ++} ++ ++// 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 ++ ++ 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), ++ ++ 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 != "" { ++ out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id)) ++ } else if options.flags&HTML_TOC != 0 { ++ // headerCount is incremented in htmlTocHeader ++ out.WriteString(fmt.Sprintf("<h%d id=\"toc_%d\">", level, options.headerCount)) ++ } 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.TocHeader(out.Bytes()[tocMarker:], level) ++ } ++ ++ 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) { ++ if options.flags&HTML_GITHUB_BLOCKCODE != 0 { ++ options.BlockCodeGithub(out, text, lang) ++ } else { ++ options.BlockCodeNormal(out, text, lang) ++ } ++} ++ ++func (options *Html) BlockCodeNormal(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=\"") ++ } 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") ++} ++ ++// GitHub style code block: ++// ++// <pre lang="LANG"><code> ++// ... ++// </code></pre> ++// ++// Unlike other parsers, we store the language identifier in the <pre>, ++// and don't let the user generate custom classes. ++// ++// The language identifier in the <pre> block gets postprocessed and all ++// the code inside gets syntax highlighted with Pygments. This is much safer ++// than letting the user specify a CSS class for highlighting. ++// ++// Note that we only generate HTML for the first specifier. ++// E.g. ++// ~~~~ {.python .numbered} => <pre lang="python"><code> ++func (options *Html) BlockCodeGithub(out *bytes.Buffer, text []byte, lang string) { ++ doubleSpace(out) ++ ++ // parse out the language name ++ count := 0 ++ for _, elt := range strings.Fields(lang) { ++ if elt[0] == '.' { ++ elt = elt[1:] ++ } ++ if len(elt) == 0 { ++ continue ++ } ++ out.WriteString("<pre lang=\"") ++ attrEscape(out, []byte(elt)) ++ out.WriteString("\"><code>") ++ count++ ++ break ++ } ++ ++ if count == 0 { ++ out.WriteString("<pre><code>") ++ } ++ ++ 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) ++ ++ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) { ++ out.WriteString("\" rel=\"nofollow") ++ } ++ // 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) { ++ 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) ++ } ++ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) { ++ out.WriteString("\" rel=\"nofollow") ++ } ++ // 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) TocHeader(text []byte, level int) { ++ 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=\"#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) 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) { ++ yes = false ++ ++ // a tag begin with '#' ++ if link[0] == '#' { ++ yes = true ++ } ++ ++ // link begin with '/' but not '//', the second maybe a protocol relative link ++ if len(link) >= 2 && link[0] == '/' && link[1] != '/' { ++ yes = true ++ } ++ ++ // only the root '/' ++ if len(link) == 1 && link[0] == '/' { ++ yes = true ++ } ++ return ++} +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..8197110 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/inline.go +@@ -0,0 +1,1078 @@ ++// ++// 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) ++ ++ // should there be a hard line break here? ++ if p.flags&EXTENSION_HARD_LINE_BREAK == 0 && end-eol < 2 { ++ return 0 ++ } ++ ++ 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) && data[i] == '[': ++ 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://"), []byte("/")} ++ ++func isSafeLink(link []byte) bool { ++ 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 { ++ tmpI = 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..eab7698 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/inline_test.go +@@ -0,0 +1,796 @@ ++// ++// 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) ++} ++ ++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 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 has an \nextra space\n", ++ "<p>this has an<br />\nextra space</p>\n", ++ } ++ doTestsInline(t, tests) ++} ++ ++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", ++ ++ "\n", ++ "<p><img src=\"/bar/\" alt=\"foo\" />\n</p>\n", ++ ++ "\n", ++ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", ++ ++ "\n", ++ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", ++ ++ "\n", ++ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", ++ ++ "\n", ++ "<p><img src=\"/bar/ title with no quotes\" alt=\"foo with a title\" />\n</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", ++ ++ "[](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", ++ } ++ doLinkTestsInline(t, tests) ++ ++} ++ ++func TestNofollowLink(t *testing.T) { ++ var tests = []string{ ++ "[foo](http://bar.com/foo/)\n", ++ "<p><a href=\"http://bar.com/foo/\" rel=\"nofollow\">foo</a></p>\n", ++ } ++ doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS|HTML_SANITIZE_OUTPUT, ++ HtmlRendererParameters{}) ++ // HTML_SANITIZE_OUTPUT won't allow relative links, so test that separately: ++ tests = []string{ ++ "[foo](/bar/)\n", ++ "<p><a href=\"/bar/\">foo</a></p>\n", ++ } ++ doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS, HtmlRendererParameters{}) ++} ++ ++func TestHrefTargetBlank(t *testing.T) { ++ var tests = []string{ ++ // internal link ++ "[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](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", ++ } ++ 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", ++} ++ ++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) ++} +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..023c056 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/markdown.go +@@ -0,0 +1,845 @@ ++// ++// 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 ++) ++ ++// 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 ++ htmlFlags := 0 ++ htmlFlags |= HTML_USE_XHTML ++ htmlFlags |= HTML_USE_SMARTYPANTS ++ htmlFlags |= HTML_SMARTYPANTS_FRACTIONS ++ htmlFlags |= HTML_SMARTYPANTS_LATEX_DASHES ++ htmlFlags |= HTML_SANITIZE_OUTPUT ++ renderer := HtmlRenderer(htmlFlags, "", "") ++ ++ // set up the parser ++ extensions := 0 ++ extensions |= EXTENSION_NO_INTRA_EMPHASIS ++ extensions |= EXTENSION_TABLES ++ extensions |= EXTENSION_FENCED_CODE ++ extensions |= EXTENSION_AUTOLINK ++ extensions |= EXTENSION_STRIKETHROUGH ++ extensions |= EXTENSION_SPACE_HEADERS ++ extensions |= EXTENSION_HEADER_IDS ++ ++ return Markdown(input, renderer, extensions) ++} ++ ++// 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) ++ ++ if renderer.GetFlags()&HTML_SANITIZE_OUTPUT != 0 { ++ second = sanitizeHtmlSafe(second) ++ } ++ ++ 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 { ++ // tmp var so we don't modify beyond bounds of `input` ++ var tmp = make([]byte, len(input[beg:]), len(input[beg:])+1) ++ copy(tmp, input[beg:]) ++ if i := p.fencedCode(&out, append(tmp, '\n'), 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/sanitize.go b/vendor/src/github.com/russross/blackfriday/sanitize.go +new file mode 100644 +index 0000000..ce6ef7b +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/sanitize.go +@@ -0,0 +1,154 @@ ++package blackfriday ++ ++import ( ++ "bufio" ++ "bytes" ++ "code.google.com/p/go.net/html" ++ "fmt" ++ "io" ++) ++ ++// Whitelisted element tags, attributes on particular tags, attributes that are ++// interpreted as protocols (again on particular tags), and allowed protocols. ++var ( ++ whitelistTags map[string]bool ++ whitelistAttrs map[string]map[string]bool ++ protocolAttrs map[string]map[string]bool ++ whitelistProtocols [][]byte ++) ++ ++func init() { ++ whitelistTags = toSet([]string{ ++ // Headings ++ "h1", "h2", "h3", "h4", "h5", "h6", ++ // Block elements ++ "p", "pre", "blockquote", "hr", "div", "header", "article", "aside", "footer", ++ "section", "main", "mark", "figure", "figcaption", ++ // Inline elements ++ "a", "br", "cite", "code", "img", ++ // Lists ++ "ol", "ul", "li", ++ // Tables ++ "table", "tbody", "td", "tfoot", "th", "thead", "tr", "colgroup", "col", "caption", ++ // Formatting ++ "u", "i", "em", "small", "strike", "b", "strong", "sub", "sup", "q", ++ // Definition lists ++ "dd", "dl", "dt", ++ }) ++ whitelistAttrs = map[string]map[string]bool{ ++ "a": toSet([]string{"href", "title", "rel"}), ++ "img": toSet([]string{"src", "alt", "title"}), ++ "td": toSet([]string{"align"}), ++ "th": toSet([]string{"align"}), ++ } ++ protocolAttrs = map[string]map[string]bool{ ++ "a": toSet([]string{"href"}), ++ "img": toSet([]string{"src"}), ++ } ++ whitelistProtocols = [][]byte{ ++ []byte("http://"), ++ []byte("https://"), ++ []byte("ftp://"), ++ []byte("mailto:"), ++ } ++} ++ ++func toSet(keys []string) map[string]bool { ++ m := make(map[string]bool, len(keys)) ++ for _, k := range keys { ++ m[k] = true ++ } ++ return m ++} ++ ++// Sanitizes the given input by parsing it as HTML5, then whitelisting known to ++// be safe elements and attributes. All other HTML is escaped, unsafe attributes ++// are stripped. ++func sanitizeHtmlSafe(input []byte) []byte { ++ r := bytes.NewReader(input) ++ var w bytes.Buffer ++ tokenizer := html.NewTokenizer(r) ++ wr := bufio.NewWriter(&w) ++ ++ // Iterate through all tokens in the input stream and sanitize them. ++ for t := tokenizer.Next(); t != html.ErrorToken; t = tokenizer.Next() { ++ switch t { ++ case html.TextToken: ++ // Text is written escaped. ++ wr.WriteString(tokenizer.Token().String()) ++ case html.SelfClosingTagToken, html.StartTagToken: ++ // HTML tags are escaped unless whitelisted. ++ tag, hasAttributes := tokenizer.TagName() ++ tagName := string(tag) ++ if whitelistTags[tagName] { ++ wr.WriteString("<") ++ wr.Write(tag) ++ for hasAttributes { ++ var key, val []byte ++ key, val, hasAttributes = tokenizer.TagAttr() ++ attrName := string(key) ++ // Only include whitelisted attributes for the given tagName. ++ tagWhitelistedAttrs, ok := whitelistAttrs[tagName] ++ if ok && tagWhitelistedAttrs[attrName] { ++ // For whitelisted attributes, if it's an attribute that requires ++ // protocol checking, do so and strip it if it's not known to be safe. ++ tagProtocolAttrs, ok := protocolAttrs[tagName] ++ if ok && tagProtocolAttrs[attrName] { ++ if !isRelativeLink(val) && !protocolAllowed(val) { ++ continue ++ } ++ } ++ wr.WriteByte(' ') ++ wr.Write(key) ++ wr.WriteString(`="`) ++ wr.WriteString(html.EscapeString(string(val))) ++ wr.WriteByte('"') ++ } ++ } ++ if t == html.SelfClosingTagToken { ++ wr.WriteString("/>") ++ } else { ++ wr.WriteString(">") ++ } ++ } else { ++ wr.WriteString(html.EscapeString(string(tokenizer.Raw()))) ++ } ++ // Make sure that tags like <script> that switch the parser into raw mode ++ // do not destroy the parse mode for following HTML text (the point is to ++ // escape them anyway). For that, switch off raw mode in the tokenizer. ++ tokenizer.NextIsNotRawText() ++ case html.EndTagToken: ++ // Whitelisted tokens can be written in raw. ++ tag, _ := tokenizer.TagName() ++ if whitelistTags[string(tag)] { ++ wr.Write(tokenizer.Raw()) ++ } else { ++ wr.WriteString(html.EscapeString(string(tokenizer.Raw()))) ++ } ++ case html.CommentToken: ++ // Comments are not really expected, but harmless. ++ wr.Write(tokenizer.Raw()) ++ case html.DoctypeToken: ++ // Escape DOCTYPES, entities etc can be dangerous ++ wr.WriteString(html.EscapeString(string(tokenizer.Raw()))) ++ default: ++ tokenizer.Token() ++ panic(fmt.Errorf("Unexpected token type %v", t)) ++ } ++ } ++ err := tokenizer.Err() ++ if err != nil && err != io.EOF { ++ panic(tokenizer.Err()) ++ } ++ wr.Flush() ++ return w.Bytes() ++} ++ ++func protocolAllowed(attr []byte) bool { ++ for _, prefix := range whitelistProtocols { ++ if bytes.HasPrefix(attr, prefix) { ++ return true ++ } ++ } ++ return false ++} +diff --git a/vendor/src/github.com/russross/blackfriday/sanitize_test.go b/vendor/src/github.com/russross/blackfriday/sanitize_test.go +new file mode 100644 +index 0000000..6d248c1 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/sanitize_test.go +@@ -0,0 +1,199 @@ ++package blackfriday ++ ++import ( ++ "testing" ++) ++ ++func doTestsSanitize(t *testing.T, tests []string) { ++ doTestsInlineParam(t, tests, 0, HTML_SKIP_STYLE|HTML_SANITIZE_OUTPUT, HtmlRendererParameters{}) ++} ++ ++func TestSanitizeRawHtmlTag(t *testing.T) { ++ tests := []string{ ++ "zz <style>p {}</style>\n", ++ "<p>zz <style>p {}</style></p>\n", ++ ++ "zz <STYLE>p {}</STYLE>\n", ++ "<p>zz <style>p {}</style></p>\n", ++ ++ "<SCRIPT>alert()</SCRIPT>\n", ++ "<p><script>alert()</script></p>\n", ++ ++ "zz <SCRIPT>alert()</SCRIPT>\n", ++ "<p>zz <script>alert()</script></p>\n", ++ ++ "zz <script>alert()</script>\n", ++ "<p>zz <script>alert()</script></p>\n", ++ ++ " <script>alert()</script>\n", ++ "<p><script>alert()</script></p>\n", ++ ++ "<script>alert()</script>\n", ++ "<script>alert()</script>\n", ++ ++ "<script src='foo'></script>\n", ++ "<script src='foo'></script>\n", ++ ++ "<script src='a>b'></script>\n", ++ "<script src='a>b'></script>\n", ++ ++ "zz <script src='foo'></script>\n", ++ "<p>zz <script src='foo'></script></p>\n", ++ ++ "zz <script src=foo></script>\n", ++ "<p>zz <script src=foo></script></p>\n", ++ ++ `<script><script src="http://example.com/exploit.js"></SCRIPT></script>`, ++ "<script><script src="http://example.com/exploit.js"></script></script>\n", ++ ++ `'';!--"<XSS>=&{()}`, ++ "<p>'';!--"<xss>=&{()}</p>\n", ++ ++ "<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>", ++ "<p><script SRC=http://ha.ckers.org/xss.js></script></p>\n", ++ ++ "<SCRIPT \nSRC=http://ha.ckers.org/xss.js></SCRIPT>", ++ "<p><script \nSRC=http://ha.ckers.org/xss.js></script></p>\n", ++ ++ `<IMG SRC="javascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ "<IMG SRC=javascript:alert('XSS')>", ++ "<p><img></p>\n", ++ ++ "<IMG SRC=JaVaScRiPt:alert('XSS')>", ++ "<p><img></p>\n", ++ ++ "<IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>", ++ "<p><img></p>\n", ++ ++ `<a onmouseover="alert(document.cookie)">xss link</a>`, ++ "<p><a>xss link</a></p>\n", ++ ++ "<a onmouseover=alert(document.cookie)>xss link</a>", ++ "<p><a>xss link</a></p>\n", ++ ++ `<IMG """><SCRIPT>alert("XSS")</SCRIPT>">`, ++ "<p><img><script>alert("XSS")</script>"></p>\n", ++ ++ "<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>", ++ "<p><img></p>\n", ++ ++ `<IMG SRC=# onmouseover="alert('xxs')">`, ++ "<p><img src=\"#\"></p>\n", ++ ++ `<IMG SRC= onmouseover="alert('xxs')">`, ++ "<p><img></p>\n", ++ ++ `<IMG onmouseover="alert('xxs')">`, ++ "<p><img></p>\n", ++ ++ "<IMG SRC=javascript:alert('XSS')>", ++ "<p><img></p>\n", ++ ++ "<IMG SRC=javascript:alert('XSS')>", ++ "<p><img></p>\n", ++ ++ "<IMG SRC=javascript:alert('XSS')>", ++ "<p><img></p>\n", ++ ++ `<IMG SRC="javascriptascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ `<IMG SRC="jav	ascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ `<IMG SRC="jav
ascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ `<IMG SRC="jav
ascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ `<IMG SRC="  javascript:alert('XSS');">`, ++ "<p><img></p>\n", ++ ++ `<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>`, ++ "<p><script/XSS SRC="http://ha.ckers.org/xss.js"></script></p>\n", ++ ++ "<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>", ++ "<p><body onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert("XSS")></p>\n", ++ ++ `<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>`, ++ "<p><script/SRC="http://ha.ckers.org/xss.js"></script></p>\n", ++ ++ `<<SCRIPT>alert("XSS");//<</SCRIPT>`, ++ "<p><<script>alert("XSS");//<</script></p>\n", ++ ++ "<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >", ++ "<p><script SRC=http://ha.ckers.org/xss.js?< B ></p>\n", ++ ++ "<SCRIPT SRC=//ha.ckers.org/.j>", ++ "<p><script SRC=//ha.ckers.org/.j></p>\n", ++ ++ `<IMG SRC="javascript:alert('XSS')"`, ++ "<p><IMG SRC="javascript:alert('XSS')"</p>\n", ++ ++ "<iframe src=http://ha.ckers.org/scriptlet.html <", ++ // The hyperlink gets linkified, the <iframe> gets escaped ++ "<p><iframe src=<a href=\"http://ha.ckers.org/scriptlet.html\">http://ha.ckers.org/scriptlet.html</a> <</p>\n", ++ ++ // Additonal token types: SelfClosing, Comment, DocType. ++ "<br/>", ++ "<p><br/></p>\n", ++ ++ "<!-- Comment -->", ++ "<!-- Comment -->\n", ++ ++ "<!DOCTYPE test>", ++ "<p><!DOCTYPE test></p>\n", ++ } ++ doTestsSanitize(t, tests) ++} ++ ++func TestSanitizeQuoteEscaping(t *testing.T) { ++ tests := []string{ ++ // Make sure quotes are transported correctly (different entities or ++ // unicode, but correct semantics) ++ "<p>Here are some "quotes".</p>\n", ++ "<p>Here are some "quotes".</p>\n", ++ ++ "<p>Here are some “quotes”.</p>\n", ++ "<p>Here are some \u201Cquotes\u201D.</p>\n", ++ ++ // Within a <script> tag, content gets parsed by the raw text parsing rules. ++ // This test makes sure we correctly disable those parsing rules and do not ++ // escape e.g. the closing </p>. ++ `Here are <script> some "quotes".`, ++ "<p>Here are <script> some "quotes".</p>\n", ++ ++ // Same test for an unknown element that does not switch into raw mode. ++ `Here are <eviltag> some "quotes".`, ++ "<p>Here are <eviltag> some "quotes".</p>\n", ++ } ++ doTestsSanitize(t, tests) ++} ++ ++func TestSanitizeSelfClosingTag(t *testing.T) { ++ tests := []string{ ++ "<hr>\n", ++ "<hr>\n", ++ ++ "<hr/>\n", ++ "<hr/>\n", ++ ++ // Make sure that evil attributes are stripped for self closing tags. ++ "<hr onclick=\"evil()\"/>\n", ++ "<hr/>\n", ++ } ++ doTestsSanitize(t, tests) ++} ++ ++func TestSanitizeInlineLink(t *testing.T) { ++ tests := []string{ ++ "[link](javascript:evil)", ++ "<p><a>link</a></p>\n", ++ "[link](/abc)", ++ "<p><a href=\"/abc\">link</a></p>\n", ++ } ++ doTestsSanitize(t, tests) ++} +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..d6f4ad9 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/smartypants.go +@@ -0,0 +1,376 @@ ++// ++// 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 smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { ++ if bytes.HasPrefix(text, []byte(""")) { ++ nextChar := byte(0) ++ if len(text) >= 7 { ++ nextChar = text[6] ++ } ++ if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { ++ return 5 ++ } ++ } ++ ++ if bytes.HasPrefix(text, []byte("�")) { ++ return 3 ++ } ++ ++ out.WriteByte('&') ++ return 0 ++} ++ ++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) && 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) ++ 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]) { ++ 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) && len(text) >= 3 { ++ if text[0] == '1' && text[1] == '/' && text[2] == '2' { ++ if len(text) < 4 || wordBoundary(text[3]) { ++ out.WriteString("½") ++ return 2 ++ } ++ } ++ ++ if text[0] == '1' && text[1] == '/' && text[2] == '4' { ++ if len(text) < 4 || wordBoundary(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]) || (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 smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { ++ nextChar := byte(0) ++ if len(text) > 1 { ++ nextChar = text[1] ++ } ++ if !smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { ++ out.WriteString(""") ++ } ++ ++ return 0 ++} ++ ++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) ++ r['"'] = smartDoubleQuote ++ r['&'] = smartAmp ++ 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/upskirtref/Amps and angle encoding.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Amps and angle encoding.html +new file mode 100644 +index 0000000..483f8ff +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Amps and angle encoding.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Amps and angle encoding.text +new file mode 100644 +index 0000000..0e9527f +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Auto links.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Auto links.html +new file mode 100644 +index 0000000..b1791e7 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Auto links.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Auto links.text +new file mode 100644 +index 0000000..abbc488 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Backslash escapes.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Backslash escapes.html +new file mode 100644 +index 0000000..a73c998 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Backslash escapes.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Backslash escapes.text +new file mode 100644 +index 0000000..04c20bd +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Blockquotes with code blocks.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Blockquotes with code blocks.html +new file mode 100644 +index 0000000..360fa9b +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Blockquotes with code blocks.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Blockquotes with code blocks.text +new file mode 100644 +index 0000000..c31d171 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Code Blocks.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Code Blocks.html +new file mode 100644 +index 0000000..32703f5 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Code Blocks.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Code Blocks.text +new file mode 100644 +index 0000000..b54b092 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Code Spans.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Code Spans.html +new file mode 100644 +index 0000000..ef85f95 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Code Spans.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Code Spans.text +new file mode 100644 +index 0000000..750a197 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Hard-wrapped paragraphs with list-like lines no empty line before block.html b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/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/upskirtref/Hard-wrapped paragraphs with list-like lines no empty line before block.text b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/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/upskirtref/Hard-wrapped paragraphs with list-like lines.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines.html +new file mode 100644 +index 0000000..e21ac79 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Hard-wrapped paragraphs with list-like lines.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Hard-wrapped paragraphs with list-like lines.text +new file mode 100644 +index 0000000..f8a5b27 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Horizontal rules.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Horizontal rules.html +new file mode 100644 +index 0000000..e60d4ba +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Horizontal rules.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Horizontal rules.text +new file mode 100644 +index 0000000..1594bda +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/Horizontal rules.text +@@ -0,0 +1,67 @@ ++Dashes: ++ ++--- ++ ++ --- ++ ++ --- ++ ++ --- ++ ++ --- ++ ++- - - ++ ++ - - - ++ ++ - - - ++ ++ - - - ++ ++ - - - ++ ++ ++Asterisks: ++ ++*** ++ ++ *** ++ ++ *** ++ ++ *** ++ ++ *** ++ ++* * * ++ ++ * * * ++ ++ * * * ++ ++ * * * ++ ++ * * * ++ ++ ++Underscores: ++ ++___ ++ ++ ___ ++ ++ ___ ++ ++ ___ ++ ++ ___ ++ ++_ _ _ ++ ++ _ _ _ ++ ++ _ _ _ ++ ++ _ _ _ ++ ++ _ _ _ +diff --git a/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Advanced).html b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Advanced).html +new file mode 100644 +index 0000000..3af9caf +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Inline HTML (Advanced).text b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Advanced).text +new file mode 100644 +index 0000000..86b7206 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Inline HTML (Simple).html b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Simple).html +new file mode 100644 +index 0000000..6bf78f8 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Inline HTML (Simple).text b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML (Simple).text +new file mode 100644 +index 0000000..14aa2dc +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Inline HTML comments.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML comments.html +new file mode 100644 +index 0000000..3f167a1 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Inline HTML comments.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Inline HTML comments.text +new file mode 100644 +index 0000000..41d830d +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, inline style.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, inline style.html +new file mode 100644 +index 0000000..5802f2d +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, inline style.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, inline style.text +new file mode 100644 +index 0000000..09017a9 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, reference style.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, reference style.html +new file mode 100644 +index 0000000..bebefde +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, reference style.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, reference style.text +new file mode 100644 +index 0000000..341ec88 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, shortcut references.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, shortcut references.html +new file mode 100644 +index 0000000..0b5e1d6 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Links, shortcut references.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Links, shortcut references.text +new file mode 100644 +index 0000000..8c44c98 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Literal quotes in titles.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Literal quotes in titles.html +new file mode 100644 +index 0000000..611c1ac +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Literal quotes in titles.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Literal quotes in titles.text +new file mode 100644 +index 0000000..29d0e42 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Markdown Documentation - Basics.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Basics.html +new file mode 100644 +index 0000000..ea3a61c +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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> ++</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/upskirtref/Markdown Documentation - Basics.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Basics.text +new file mode 100644 +index 0000000..486055c +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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): ++ ++  ++ ++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/upskirtref/Markdown Documentation - Syntax.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Syntax.html +new file mode 100644 +index 0000000..61dde59 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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> ++ ++ ++</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/upskirtref/Markdown Documentation - Syntax.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Markdown Documentation - Syntax.text +new file mode 100644 +index 0000000..57360a1 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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: ++ ++  ++ ++  ++ ++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/upskirtref/Nested blockquotes.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Nested blockquotes.html +new file mode 100644 +index 0000000..538bb4f +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Nested blockquotes.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Nested blockquotes.text +new file mode 100644 +index 0000000..ed3c624 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/Nested blockquotes.text +@@ -0,0 +1,5 @@ ++> foo ++> ++> > bar ++> ++> foo +diff --git a/vendor/src/github.com/russross/blackfriday/upskirtref/Ordered and unordered lists.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Ordered and unordered lists.html +new file mode 100644 +index 0000000..d6fa427 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Ordered and unordered lists.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Ordered and unordered lists.text +new file mode 100644 +index 0000000..7f3b497 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Strong and em together.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Strong and em together.html +new file mode 100644 +index 0000000..71ec78c +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Strong and em together.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Strong and em together.text +new file mode 100644 +index 0000000..95ee690 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Tabs.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Tabs.html +new file mode 100644 +index 0000000..64006d9 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Tabs.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Tabs.text +new file mode 100644 +index 0000000..589d113 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Tidyness.html b/vendor/src/github.com/russross/blackfriday/upskirtref/Tidyness.html +new file mode 100644 +index 0000000..9c45b69 +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/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/upskirtref/Tidyness.text b/vendor/src/github.com/russross/blackfriday/upskirtref/Tidyness.text +new file mode 100644 +index 0000000..5f18b8d +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref/Tidyness.text +@@ -0,0 +1,5 @@ ++> A list within a blockquote: ++> ++> * asterisk 1 ++> * asterisk 2 ++> * asterisk 3 +diff --git a/vendor/src/github.com/russross/blackfriday/upskirtref_test.go b/vendor/src/github.com/russross/blackfriday/upskirtref_test.go +new file mode 100644 +index 0000000..42a0bdd +--- /dev/null ++++ b/vendor/src/github.com/russross/blackfriday/upskirtref_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("upskirtref", 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("upskirtref", 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/SOURCES/secrets.patch b/SOURCES/secrets.patch new file mode 100644 index 0000000..dd5e12e --- /dev/null +++ b/SOURCES/secrets.patch @@ -0,0 +1,217 @@ +From ed97ccf535888a5e1fa2cadf42d01089e1192e06 Mon Sep 17 00:00:00 2001 +From: Dan Walsh <dwalsh@redhat.com> +Date: Thu, 13 Nov 2014 15:28:39 -0500 +Subject: [PATCH] Super Secrets Patch + +Docker-DCO-1.1-Signed-off-by: Dan Walsh <dwalsh@redhat.com> (github: rhatdan) +--- + daemon/container.go | 48 +++++++++++++++++++++++++++++- + daemon/secrets.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + daemon/volumes.go | 11 +++++++ + graph/graph.go | 1 + + 4 files changed, 145 insertions(+), 1 deletion(-) + create mode 100644 daemon/secrets.go + +diff --git a/daemon/container.go b/daemon/container.go +index 2ac8316..b754105 100644 +--- a/daemon/container.go ++++ b/daemon/container.go +@@ -338,11 +338,28 @@ func (container *Container) Start() (err error) { + if err := populateCommand(container, env); err != nil { + return err + } ++ if err := container.setupSecretFiles(); err != nil { ++ return err ++ } + if err := container.setupMounts(); err != nil { + return err + } + +- return container.waitForStart() ++ if err := container.waitForStart(); err != nil { ++ return err ++ } ++ ++ // Now the container is running, unmount the secrets on the host ++ secretsPath, err := container.secretsPath() ++ if err != nil { ++ return err ++ } ++ ++ if err := syscall.Unmount(secretsPath, syscall.MNT_DETACH); err != nil { ++ return err ++ } ++ ++ return nil + } + + func (container *Container) Run() error { +@@ -793,6 +810,10 @@ func (container *Container) jsonPath() (string, error) { + return container.getRootResourcePath("config.json") + } + ++func (container *Container) secretsPath() (string, error) { ++ return container.getRootResourcePath("secrets") ++} ++ + // This method must be exported to be used from the lxc template + // This directory is only usable when the container is running + func (container *Container) RootfsPath() string { +@@ -1064,6 +1085,31 @@ func (container *Container) verifyDaemonSettings() { + } + } + ++func (container *Container) setupSecretFiles() error { ++ secretsPath, err := container.secretsPath() ++ if err != nil { ++ return err ++ } ++ ++ if err := os.MkdirAll(secretsPath, 0700); err != nil { ++ return err ++ } ++ ++ if err := syscall.Mount("tmpfs", secretsPath, "tmpfs", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), label.FormatMountLabel("", container.GetMountLabel())); err != nil { ++ return fmt.Errorf("mounting secret tmpfs: %s", err) ++ } ++ ++ data, err := getHostSecretData() ++ if err != nil { ++ return err ++ } ++ for _, s := range data { ++ s.SaveTo(secretsPath) ++ } ++ ++ return nil ++} ++ + func (container *Container) setupLinkedContainers() ([]string, error) { + var ( + env []string +diff --git a/daemon/secrets.go b/daemon/secrets.go +new file mode 100644 +index 0000000..8bd97a5 +--- /dev/null ++++ b/daemon/secrets.go +@@ -0,0 +1,86 @@ ++package daemon ++ ++import ( ++ "io/ioutil" ++ "os" ++ "path/filepath" ++) ++ ++type Secret struct { ++ Name string ++ IsDir bool ++ HostBased bool ++} ++ ++type SecretData struct { ++ Name string ++ Data []byte ++} ++ ++func (s SecretData) SaveTo(dir string) error { ++ path := filepath.Join(dir, s.Name) ++ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil && !os.IsExist(err) { ++ return err ++ } ++ if err := ioutil.WriteFile(path, s.Data, 0755); err != nil { ++ return err ++ } ++ return nil ++} ++ ++func readAll(root, prefix string) ([]SecretData, error) { ++ path := filepath.Join(root, prefix) ++ ++ data := []SecretData{} ++ ++ files, err := ioutil.ReadDir(path) ++ if err != nil { ++ if os.IsNotExist(err) { ++ return data, nil ++ } ++ ++ return nil, err ++ } ++ ++ for _, f := range files { ++ fileData, err := readFile(root, filepath.Join(prefix, f.Name())) ++ if err != nil { ++ // If the file did not exist, might be a dangling symlink ++ // Ignore the error ++ if os.IsNotExist(err) { ++ continue ++ } ++ return nil, err ++ } ++ data = append(data, fileData...) ++ } ++ ++ return data, nil ++} ++ ++func readFile(root, name string) ([]SecretData, error) { ++ path := filepath.Join(root, name) ++ ++ s, err := os.Stat(path) ++ if err != nil { ++ return nil, err ++ } ++ ++ if s.IsDir() { ++ dirData, err := readAll(root, name) ++ if err != nil { ++ return nil, err ++ } ++ return dirData, nil ++ } else { ++ bytes, err := ioutil.ReadFile(path) ++ if err != nil { ++ return nil, err ++ } ++ return []SecretData{{Name: name, Data: bytes}}, nil ++ } ++} ++ ++func getHostSecretData() ([]SecretData, error) { ++ return readAll("/usr/share/rhel/secrets", "") ++} +diff --git a/daemon/volumes.go b/daemon/volumes.go +index 6523dae..322d3f4 100644 +--- a/daemon/volumes.go ++++ b/daemon/volumes.go +@@ -260,6 +260,17 @@ func (container *Container) setupMounts() error { + }) + } + ++ secretsPath, err := container.secretsPath() ++ if err != nil { ++ return err ++ } ++ ++ mounts = append(mounts, execdriver.Mount{ ++ Source: secretsPath, ++ Destination: "/run/secrets", ++ Writable: true, ++ }) ++ + container.command.Mounts = mounts + return nil + } +diff --git a/graph/graph.go b/graph/graph.go +index 720f6e6..647b64d 100644 +--- a/graph/graph.go ++++ b/graph/graph.go +@@ -242,6 +242,7 @@ func SetupInitLayer(initLayer string) error { + "/etc/hostname": "file", + "/dev/console": "file", + "/etc/mtab": "/proc/mounts", ++ "/run/secrets": "dir", + } { + parts := strings.Split(pth, "/") + prev := "/" diff --git a/SPECS/docker.spec b/SPECS/docker.spec index f8870c3..e165ef3 100644 --- a/SPECS/docker.spec +++ b/SPECS/docker.spec @@ -2,58 +2,50 @@ %global __os_install_post %{_rpmconfigdir}/brp-compress #debuginfo not supported with Go -%global debug_package %{nil} -%global gopath %{_datadir}/gocode +%global debug_package %{nil} +%global provider_tld com +%global provider github +%global project docker +%global repo docker +%global common_path %{provider}.%{provider_tld}/%{project} -%global import_path github.com/docker/docker -%global commit 2a2f26c1979cdaed884c765ea3dd203543e7e284 -%global shortcommit %(c=%{commit}; echo ${c:0:7}) +%global import_path %{common_path}/%{repo} +%global import_path_libcontainer %{common_path}/libcontainer -Name: docker -Version: 1.2.0 -Release: 1.8%{?dist} -Summary: Automates deployment of containerized applications -License: ASL 2.0 +%global commit 39fa2faad2f3d6fa5133de4eb740677202f53ef4 +%global shortcommit %(c=%{commit}; echo ${c:0:7}) -URL: http://www.docker.io +Name: docker +Version: 1.3.2 +Release: 4%{?dist} +Summary: Automates deployment of containerized applications +License: ASL 2.0 +URL: http://www.docker.com # only x86_64 for now: https://github.com/docker/docker/issues/136 ExclusiveArch: x86_64 -Source0: https://github.com/rhatdan/docker/archive/%{commit}/docker-%{shortcommit}.tar.gz -Patch1: 0001-On-Red-Hat-Registry-Servers-we-return-404-on-certifi.patch -Patch2: docker-reverse-entitlement.patch -# though final name for sysconf/sysvinit files is simply 'docker', -# having .sysvinit and .sysconfig makes things clear -Source1: docker.service -Source2: docker-man-3.tar.gz -Source3: docker.sysconfig -# docker: systemd socket activation results in privilege escalation -Source4: docker.socket -Source5: codegansta.tgz -Source6: docker-storage.sysconfig -BuildRequires: gcc +Source0: https://%{import_path}/archive/v%{version}.tar.gz +Patch1: go-md2man.patch +Patch2: 0007-validate-image-ID-properly-before-load.patch +Patch3: secrets.patch +Source1: docker.service +Source2: codegansta.tgz +Source3: docker.sysconfig +Source5: docker-storage.sysconfig BuildRequires: glibc-static -# ensure build uses golang 1.2-7 and above -# http://code.google.com/p/go/source/detail?r=a15f344a9efa35ef168c8feaa92a15a1cdc93db5 BuildRequires: golang >= 1.3.1 -BuildRequires: golang(github.com/gorilla/mux) >= 0-0.12 -BuildRequires: golang(github.com/kr/pty) >= 0-0.19 -BuildRequires: golang(code.google.com/p/go.net/websocket) -BuildRequires: golang(code.google.com/p/gosqlite/sqlite3) -BuildRequires: golang(github.com/syndtr/gocapability/capability) >= 0-0.5 -BuildRequires: golang(github.com/godbus/dbus) -BuildRequires: golang(github.com/coreos/go-systemd/activation) >= 2-1 -#BuildRequires: golang(github.com/codegangsta/cli) BuildRequires: device-mapper-devel BuildRequires: btrfs-progs-devel +BuildRequires: sqlite-devel BuildRequires: pkgconfig(systemd) -Requires: systemd-units +# appropriate systemd version as per rhbz#1171054 +Requires: systemd-units >= 208-11.el7_0.5 # need xz to work with ubuntu images -Requires: xz - -Provides: lxc-docker = %{version} -Provides: docker -Provides: docker-io -Provides: nsinit +Requires: xz +Requires: device-mapper-libs >= 1.02.90-1 +Provides: lxc-docker = %{version} +Provides: docker = %{version} +Provides: docker-io = %{version} +Provides: nsinit %description Docker is an open-source engine that automates the deployment of any @@ -66,73 +58,114 @@ and tests on a laptop will run at scale, in production*, on VMs, bare-metal servers, OpenStack clusters, public instances, or combinations of the above. %package devel -BuildRequires: golang -Summary: A golang registry for global request variables (source libraries) -Provides: docker-pkg-devel docker-io-pkg-devel -Provides: golang(github.com/docker/libcontainer) -Provides: golang(%{import_path}) = %{version}-%{release} -Provides: golang(%{import_path}/api) = %{version}-%{release} -Provides: golang(%{import_path}/api/client) = %{version}-%{release} -Provides: golang(%{import_path}/api/server) = %{version}-%{release} -Provides: golang(%{import_path}/archive) = %{version}-%{release} -Provides: golang(%{import_path}/builtins) = %{version}-%{release} -Provides: golang(%{import_path}/contrib) = %{version}-%{release} -Provides: golang(%{import_path}/contrib/docker-device-tool) = %{version}-%{release} -Provides: golang(%{import_path}/contrib/host-integration) = %{version}-%{release} -Provides: golang(%{import_path}/daemon) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver/execdrivers) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver/lxc) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver/native) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver/native/configuration) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/execdriver/native/template) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver/aufs) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver/btrfs) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver/devmapper) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver/graphtest) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/graphdriver/vfs) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/networkdriver) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/networkdriver/bridge) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/networkdriver/ipallocator) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/networkdriver/portallocator) = %{version}-%{release} -Provides: golang(%{import_path}/daemon/networkdriver/portmapper) = %{version}-%{release} -Provides: golang(%{import_path}/dockerversion) = %{version}-%{release} -Provides: golang(%{import_path}/engine) = %{version}-%{release} -Provides: golang(%{import_path}/graph) = %{version}-%{release} -Provides: golang(%{import_path}/image) = %{version}-%{release} -Provides: golang(%{import_path}/integration) = %{version}-%{release} -Provides: golang(%{import_path}/integration-cli) = %{version}-%{release} -Provides: golang(%{import_path}/links) = %{version}-%{release} -Provides: golang(%{import_path}/nat) = %{version}-%{release} -Provides: golang(%{import_path}/opts) = %{version}-%{release} -Provides: golang(%{import_path}/registry) = %{version}-%{release} -Provides: golang(%{import_path}/runconfig) = %{version}-%{release} -Provides: golang(%{import_path}/utils) = %{version}-%{release} -Provides: golang(%{import_path}/utils/broadcastwriter) = %{version}-%{release} -Provides: golang(%{import_path}/pkg) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/graphdb) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/iptables) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/listenbuffer) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/mflag) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/mflag/example) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/mount) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/namesgenerator) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/networkfs/etchosts) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/networkfs/resolvconf) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/proxy) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/signal) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/symlink) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/sysinfo) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/system) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/systemd) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/tailfile) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/term) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/testutils) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/truncindex) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/units) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/user) = %{version}-%{release} -Provides: golang(%{import_path}/pkg/version) = %{version}-%{release} +BuildRequires: golang >= 1.3.1 +Requires: golang >= 1.3.1 +Summary: A golang registry for global request variables (source libraries) +Provides: docker-pkg-devel docker-io-devel docker-io-pkg-devel +Provides: golang(%{import_path}) = %{version}-%{release} +Provides: golang(%{import_path}/api) = %{version}-%{release} +Provides: golang(%{import_path}/api/client) = %{version}-%{release} +Provides: golang(%{import_path}/api/server) = %{version}-%{release} +Provides: golang(%{import_path}/builder) = %{version}-%{release} +Provides: golang(%{import_path}/builder/parser) = %{version}-%{release} +Provides: golang(%{import_path}/builder/parser/dumper) = %{version}-%{release} +Provides: golang(%{import_path}/builtins) = %{version}-%{release} +Provides: golang(%{import_path}/contrib/docker-device-tool) = %{version}-%{release} +Provides: golang(%{import_path}/contrib/host-integration) = %{version}-%{release} +Provides: golang(%{import_path}/daemon) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/execdriver) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/execdriver/execdrivers) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/execdriver/lxc) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/execdriver/native) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/execdriver/native/template) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver/aufs) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver/btrfs) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver/devmapper) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver/graphtest) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/graphdriver/vfs) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/networkdriver) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/networkdriver/bridge) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/networkdriver/ipallocator) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/networkdriver/portallocator) = %{version}-%{release} +Provides: golang(%{import_path}/daemon/networkdriver/portmapper) = %{version}-%{release} +Provides: golang(%{import_path}/dockerversion) = %{version}-%{release} +Provides: golang(%{import_path}/engine) = %{version}-%{release} +Provides: golang(%{import_path}/events) = %{version}-%{release} +Provides: golang(%{import_path}/graph) = %{version}-%{release} +Provides: golang(%{import_path}/image) = %{version}-%{release} +Provides: golang(%{import_path}/integration) = %{version}-%{release} +Provides: golang(%{import_path}/integration-cli) = %{version}-%{release} +Provides: golang(%{import_path}/links) = %{version}-%{release} +Provides: golang(%{import_path}/nat) = %{version}-%{release} +Provides: golang(%{import_path}/opts) = %{version}-%{release} +Provides: golang(%{import_path}/registry) = %{version}-%{release} +Provides: golang(%{import_path}/runconfig) = %{version}-%{release} +Provides: golang(%{import_path}/trust) = %{version}-%{release} +Provides: golang(%{import_path}/utils) = %{version}-%{release} +Provides: golang(%{import_path}/volumes) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/archive) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/broadcastwriter) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/chrootarchive) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/fileutils) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/graphdb) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/httputils) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/ioutils) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/iptables) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/jsonlog) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/listenbuffer) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/log) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/mflag) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/mflag/example) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/mount) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/namesgenerator) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/networkfs/etchosts) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/networkfs/resolvconf) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/parsers) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/parsers/filters) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/parsers/kernel) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/parsers/operatingsystem) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/pools) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/promise) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/proxy) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/reexec) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/signal) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/stdcopy) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/symlink) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/sysinfo) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/system) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/systemd) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/tailfile) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/tarsum) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/term) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/testutils) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/timeutils) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/truncindex) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/units) = %{version}-%{release} +Provides: golang(%{import_path}/pkg/version) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/apparmor) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/cgroups) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/cgroups/fs) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/cgroups/systemd) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/console) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/devices) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/label) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/mount) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/mount/nodes) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/namespaces) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/namespaces/nsenter) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/netlink) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/network) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/nsinit) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/security/capabilities) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/security/restrict) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/selinux) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/syncpipe) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/system) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/user) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/utils) = %{version}-%{release} +Provides: golang(%{import_path_libcontainer}/xattr) = %{version}-%{release} Obsoletes: golang-github-docker-libcontainer-devel @@ -140,11 +173,12 @@ Obsoletes: golang-github-docker-libcontainer-devel This is the source libraries for docker. %prep -%setup -q -n docker-%{commit} -%patch1 -p1 -b .404 -%patch2 -p1 -b .entitlement -tar zxf %{SOURCE2} -tar zxf %{SOURCE5} +%setup -qn docker-%{version} +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +rm daemon/*.orig +tar zxf %{SOURCE2} %build mkdir _build @@ -158,15 +192,23 @@ export DOCKER_GITCOMMIT="%{shortcommit}/%{version}" export DOCKER_BUILDTAGS='selinux' export GOPATH=$(pwd)/_build:$(pwd)/vendor:%{gopath} +# build docker binary hack/make.sh dynbinary cp contrib/syntax/vim/LICENSE LICENSE-vim-syntax cp contrib/syntax/vim/README.md README-vim-syntax.md -#build nsinit pushd $(pwd)/_build/src - go build github.com/docker/libcontainer/nsinit +# build nsinit +go build github.com/docker/libcontainer/nsinit +# build go-md2man for building manpages +go build github.com/cpuguy83/go-md2man popd +cp _build/src/go-md2man docs/man/. +sed -i 's/go-md2man/.\/go-md2man/' docs/man/md2man-all.sh +# build manpages +docs/man/md2man-all.sh + %install # install binary install -d %{buildroot}%{_bindir} @@ -178,9 +220,9 @@ install -p -m 755 bundles/%{version}/dynbinary/dockerinit-%{version} %{buildroot # install manpages install -d %{buildroot}%{_mandir}/man1 -install -p -m 644 man1/* %{buildroot}%{_mandir}/man1 +install -p -m 644 docs/man/man1/* %{buildroot}%{_mandir}/man1 install -d %{buildroot}%{_mandir}/man5 -install -p -m 644 man5/* %{buildroot}%{_mandir}/man5 +install -p -m 644 docs/man/man5/* %{buildroot}%{_mandir}/man5 # install bash completion install -d %{buildroot}%{_datadir}/bash-completion/completions/ @@ -206,25 +248,25 @@ install -d -m 700 %{buildroot}%{_sharedstatedir}/docker # install systemd/init scripts install -d %{buildroot}%{_unitdir} install -p -m 644 %{SOURCE1} %{buildroot}%{_unitdir} -install -p -m 644 %{SOURCE4} %{buildroot}%{_unitdir} +install -p -m 644 contrib/init/systemd/docker.socket %{buildroot}%{_unitdir} # for additional args install -d %{buildroot}%{_sysconfdir}/sysconfig/ install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/docker -install -p -m 644 %{SOURCE6} %{buildroot}%{_sysconfdir}/sysconfig/docker-storage +install -p -m 644 %{SOURCE5} %{buildroot}%{_sysconfdir}/sysconfig/docker-storage # install secrets dir -#install -d -p -m 750 %{buildroot}/%{_datadir}/rhel/secrets +install -d -p -m 750 %{buildroot}/%{_datadir}/rhel/secrets # rhbz#1110876 - update symlinks for subscription management -#ln -s %{_sysconfdir}/pki/entitlement %{buildroot}%{_datadir}/rhel/secrets/etc-pki-entitlement -#ln -s %{_sysconfdir}/rhsm %{buildroot}%{_datadir}/rhel/secrets/rhsm -#ln -s %{_sysconfdir}/yum.repos.d/redhat.repo %{buildroot}%{_datadir}/rhel/secrets/rhel7.repo +ln -s %{_sysconfdir}/pki/entitlement %{buildroot}%{_datadir}/rhel/secrets/etc-pki-entitlement +ln -s %{_sysconfdir}/rhsm %{buildroot}%{_datadir}/rhel/secrets/rhsm +ln -s %{_sysconfdir}/yum.repos.d/redhat.repo %{buildroot}%{_datadir}/rhel/secrets/rhel7.repo -mkdir -p %{buildroot}/etc/docker/certs.d/ -#ln -s /etc/rhsm/ca/redhat-uep.pem %{buildroot}/etc/docker/certs.d/redhat.com/redhat-ca.crt +mkdir -p %{buildroot}/etc/docker/certs.d/redhat.com +ln -s /etc/rhsm/ca/redhat-uep.pem %{buildroot}/etc/docker/certs.d/redhat.com/redhat-ca.crt # Install nsinit -install -d -p %{buildroot}%{gopath}/src/github.com/docker/libcontainer/nsinit -cp -pav vendor/src/github.com/docker/libcontainer/nsinit/*.go %{buildroot}%{gopath}/src/github.com/docker/libcontainer/nsinit +install -d -p %{buildroot}%{gopath}/src/%{import_path_libcontainer}/nsinit +cp -pav vendor/src/%{import_path_libcontainer}/nsinit/*.go %{buildroot}%{gopath}/src/%{import_path_libcontainer}/nsinit install -d %{buildroot}%{_bindir} install -p -m 755 ./_build/src/nsinit %{buildroot}%{_bindir}/nsinit @@ -232,17 +274,20 @@ install -p -m 755 ./_build/src/nsinit %{buildroot}%{_bindir}/nsinit for dir in . apparmor cgroups cgroups/fs cgroups/systemd \ console devices label mount mount/nodes namespaces \ netlink network nsinit security/capabilities \ - security/restrict selinux syncpipe system user utils + security/restrict selinux syncpipe system user utils xattr do - install -d -p %{buildroot}%{gopath}/src/github.com/docker/libcontainer/$dir - cp -pav vendor/src/github.com/docker/libcontainer/$dir/*.go %{buildroot}%{gopath}/src/github.com/docker/libcontainer/$dir + install -d -p %{buildroot}%{gopath}/src/%{import_path_libcontainer}/$dir + cp -pav vendor/src/%{import_path_libcontainer}/$dir/*.go %{buildroot}%{gopath}/src/%{import_path_libcontainer}/$dir done # sources install -d -p %{buildroot}/%{gopath}/src/%{import_path} -for dir in api archive builtins daemon dockerversion engine graph \ - image links nat opts pkg registry runconfig utils +for dir in api builder builtins contrib/docker-device-tool \ + contrib/host-integration daemon docker dockerinit \ + dockerversion engine events graph \ + image links nat opts pkg registry runconfig \ + trust utils volumes do echo $dir cp -pav $dir %{buildroot}/%{gopath}/src/%{import_path}/ @@ -263,17 +308,16 @@ exit 0 %systemd_postun_with_restart docker.service %files -%defattr(-,root,root,-) %doc AUTHORS CHANGELOG.md CONTRIBUTING.md MAINTAINERS NOTICE %doc LICENSE* README*.md %{_mandir}/man1/* %{_mandir}/man5/* %{_bindir}/docker -#%dir %{_datadir}/rhel -#%dir %{_datadir}/rhel/secrets -#%{_datadir}/rhel/secrets/etc-pki-entitlement -#%{_datadir}/rhel/secrets/rhel7.repo -#%{_datadir}/rhel/secrets/rhsm +%dir %{_datadir}/rhel +%dir %{_datadir}/rhel/secrets +%{_datadir}/rhel/secrets/etc-pki-entitlement +%{_datadir}/rhel/secrets/rhel7.repo +%{_datadir}/rhel/secrets/rhsm %dir %{_libexecdir}/docker %{_libexecdir}/docker/dockerinit %{_unitdir}/docker.service @@ -281,8 +325,6 @@ exit 0 %config(noreplace) %{_sysconfdir}/sysconfig/docker %config(noreplace) %{_sysconfdir}/sysconfig/docker-storage %{_sysconfdir}/docker/certs.d -#%{_sysconfdir}/docker/certs.d/redhat.com -#%{_sysconfdir}/docker/certs.d/redhat.com/redhat-ca.crt %{_datadir}/bash-completion/completions/docker %{_datadir}/zsh/site-functions/_docker %dir %{_sharedstatedir}/docker @@ -295,247 +337,34 @@ exit 0 %dir %{_datadir}/vim/vimfiles/syntax %{_datadir}/vim/vimfiles/syntax/dockerfile.vim %{_bindir}/nsinit -%dir %{gopath}/src/github.com/docker/libcontainer/nsinit -%{gopath}/src/github.com/docker/libcontainer/nsinit/*.go -%dir %{gopath}/src/%{import_path}/runconfig -%{gopath}/src/%{import_path}/runconfig/*.go -%dir %{gopath}/src/%{import_path}/utils -%{gopath}/src/%{import_path}/utils/*.go %files devel -%dir %{gopath}/src/%{import_path} -%dir %{gopath}/src/%{import_path}/api -%{gopath}/src/%{import_path}/api/MAINTAINERS -%{gopath}/src/%{import_path}/api/README.md -%{gopath}/src/%{import_path}/api/*.go -%dir %{gopath}/src/%{import_path}/api/client -%{gopath}/src/%{import_path}/api/client/*.go -%dir %{gopath}/src/%{import_path}/api/server -%{gopath}/src/%{import_path}/api/server/MAINTAINERS -%{gopath}/src/%{import_path}/api/server/*.go -%dir %{gopath}/src/%{import_path}/archive -%{gopath}/src/%{import_path}/archive/MAINTAINERS -%{gopath}/src/%{import_path}/archive/README.md -%{gopath}/src/%{import_path}/archive/*.go -%dir %{gopath}/src/%{import_path}/archive/testdata -%{gopath}/src/%{import_path}/archive/testdata/broken.tar -%dir %{gopath}/src/%{import_path}/builtins -%{gopath}/src/%{import_path}/builtins/*.go -%dir %{gopath}/src/%{import_path}/daemon -%{gopath}/src/%{import_path}/daemon/*.go -%{gopath}/src/%{import_path}/daemon/MAINTAINERS -%{gopath}/src/%{import_path}/daemon/README.md -%dir %{gopath}/src/%{import_path}/daemon/execdriver -%{gopath}/src/%{import_path}/daemon/execdriver/*.go -%{gopath}/src/%{import_path}/daemon/execdriver/MAINTAINERS -%dir %{gopath}/src/%{import_path}/daemon/execdriver/execdrivers -%{gopath}/src/%{import_path}/daemon/execdriver/execdrivers/*.go -%dir %{gopath}/src/%{import_path}/daemon/execdriver/lxc -%{gopath}/src/%{import_path}/daemon/execdriver/lxc/MAINTAINERS -%{gopath}/src/%{import_path}/daemon/execdriver/lxc/*.go -%dir %{gopath}/src/%{import_path}/daemon/execdriver/native -%{gopath}/src/%{import_path}/daemon/execdriver/native/*.go -%dir %{gopath}/src/%{import_path}/daemon/execdriver/native/configuration -%{gopath}/src/%{import_path}/daemon/execdriver/native/configuration/*.go -%dir %{gopath}/src/%{import_path}/daemon/execdriver/native/template -%{gopath}/src/%{import_path}/daemon/execdriver/native/template/*.go -%dir %{gopath}/src/%{import_path}/daemon/graphdriver -%{gopath}/src/%{import_path}/daemon/graphdriver/*.go -%dir %{gopath}/src/%{import_path}/daemon/graphdriver/aufs -%{gopath}/src/%{import_path}/daemon/graphdriver/aufs/*.go -%dir %{gopath}/src/%{import_path}/daemon/graphdriver/btrfs -%{gopath}/src/%{import_path}/daemon/graphdriver/btrfs/*.go -%{gopath}/src/%{import_path}/daemon/graphdriver/btrfs/MAINTAINERS -%dir %{gopath}/src/%{import_path}/daemon/graphdriver/devmapper -%{gopath}/src/%{import_path}/daemon/graphdriver/devmapper/*.go -%{gopath}/src/%{import_path}/daemon/graphdriver/devmapper/MAINTAINERS -%{gopath}/src/%{import_path}/daemon/graphdriver/devmapper/README.md -%dir %{gopath}/src/%{import_path}/daemon/graphdriver/graphtest -%{gopath}/src/%{import_path}/daemon/graphdriver/graphtest/*.go -%dir %{gopath}/src/%{import_path}/daemon/graphdriver/vfs -%{gopath}/src/%{import_path}/daemon/graphdriver/vfs/*.go -%dir %{gopath}/src/%{import_path}/daemon/networkdriver -%dir %{gopath}/src/%{import_path}/daemon/networkdriver/bridge -%{gopath}/src/%{import_path}/daemon/networkdriver/bridge/*.go -%dir %{gopath}/src/%{import_path}/daemon/networkdriver/ipallocator -%{gopath}/src/%{import_path}/daemon/networkdriver/ipallocator/*.go -%{gopath}/src/%{import_path}/daemon/networkdriver/*.go -%dir %{gopath}/src/%{import_path}/daemon/networkdriver/portallocator -%{gopath}/src/%{import_path}/daemon/networkdriver/portallocator/*.go -%dir %{gopath}/src/%{import_path}/daemon/networkdriver/portmapper -%{gopath}/src/%{import_path}/daemon/networkdriver/portmapper/*.go -%dir %{gopath}/src/%{import_path}/dockerversion -%{gopath}/src/%{import_path}/dockerversion/*.go -%dir %{gopath}/src/%{import_path}/engine -%{gopath}/src/%{import_path}/engine/MAINTAINERS -%{gopath}/src/%{import_path}/engine/*.go -%dir %{gopath}/src/%{import_path}/graph -%{gopath}/src/%{import_path}/graph/MAINTAINERS -%{gopath}/src/%{import_path}/graph/*.go -%dir %{gopath}/src/%{import_path}/image -%{gopath}/src/%{import_path}/image/*.go -%dir %{gopath}/src/%{import_path}/links -%{gopath}/src/%{import_path}/links/*.go -%dir %{gopath}/src/%{import_path}/nat -%{gopath}/src/%{import_path}/nat/*.go -%dir %{gopath}/src/%{import_path}/opts -%{gopath}/src/%{import_path}/opts/*.go -%{gopath}/src/%{import_path}/registry -%dir %{gopath}/src/%{import_path}/runconfig -%{gopath}/src/%{import_path}/runconfig/*.go -%dir %{gopath}/src/%{import_path}/utils -%{gopath}/src/%{import_path}/utils/*.go -#libcontainer -%dir %{gopath}/src/github.com/docker/libcontainer -%dir %{gopath}/src/github.com/docker/libcontainer/apparmor -%dir %{gopath}/src/github.com/docker/libcontainer/cgroups -%dir %{gopath}/src/github.com/docker/libcontainer/cgroups/fs -%dir %{gopath}/src/github.com/docker/libcontainer/cgroups/systemd -%dir %{gopath}/src/github.com/docker/libcontainer/console -%dir %{gopath}/src/github.com/docker/libcontainer/devices -%dir %{gopath}/src/github.com/docker/libcontainer/label -%dir %{gopath}/src/github.com/docker/libcontainer/mount -%dir %{gopath}/src/github.com/docker/libcontainer/mount/nodes -%dir %{gopath}/src/github.com/docker/libcontainer/namespaces -%dir %{gopath}/src/github.com/docker/libcontainer/netlink -%dir %{gopath}/src/github.com/docker/libcontainer/network -%dir %{gopath}/src/github.com/docker/libcontainer/nsinit -%dir %{gopath}/src/github.com/docker/libcontainer/security -%dir %{gopath}/src/github.com/docker/libcontainer/security/capabilities -%dir %{gopath}/src/github.com/docker/libcontainer/security/restrict -%dir %{gopath}/src/github.com/docker/libcontainer/selinux -%dir %{gopath}/src/github.com/docker/libcontainer/syncpipe -%dir %{gopath}/src/github.com/docker/libcontainer/system -%dir %{gopath}/src/github.com/docker/libcontainer/user -%dir %{gopath}/src/github.com/docker/libcontainer/utils -%{gopath}/src/github.com/docker/libcontainer/*.go -%{gopath}/src/github.com/docker/libcontainer/apparmor/*.go -%{gopath}/src/github.com/docker/libcontainer/cgroups/*.go -%{gopath}/src/github.com/docker/libcontainer/cgroups/fs/*.go -%{gopath}/src/github.com/docker/libcontainer/cgroups/systemd/*.go -%{gopath}/src/github.com/docker/libcontainer/console/*.go -%{gopath}/src/github.com/docker/libcontainer/devices/*.go -%{gopath}/src/github.com/docker/libcontainer/label/*.go -%{gopath}/src/github.com/docker/libcontainer/mount/*.go -%{gopath}/src/github.com/docker/libcontainer/mount/nodes/*.go -%{gopath}/src/github.com/docker/libcontainer/namespaces/*.go -%{gopath}/src/github.com/docker/libcontainer/netlink/*.go -%{gopath}/src/github.com/docker/libcontainer/network/*.go -%{gopath}/src/github.com/docker/libcontainer/nsinit/*.go -%{gopath}/src/github.com/docker/libcontainer/security/capabilities/*.go -%{gopath}/src/github.com/docker/libcontainer/security/restrict/*.go -%{gopath}/src/github.com/docker/libcontainer/selinux/*.go -%{gopath}/src/github.com/docker/libcontainer/syncpipe/*.go -%{gopath}/src/github.com/docker/libcontainer/system/*.go -%{gopath}/src/github.com/docker/libcontainer/user/*.go -%{gopath}/src/github.com/docker/libcontainer/utils/*.go - -%dir %{gopath}/src/%{import_path} -%dir %{gopath}/src/%{import_path}/pkg -%{gopath}/src/%{import_path}/pkg/README.md -%dir %{gopath}/src/%{import_path}/pkg/broadcastwriter -%{gopath}/src/%{import_path}/pkg/broadcastwriter/*.go -%dir %{gopath}/src/%{import_path}/pkg/graphdb -%{gopath}/src/%{import_path}/pkg/graphdb/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/graphdb/*.go -%dir %{gopath}/src/%{import_path}/pkg/httputils -%{gopath}/src/%{import_path}/pkg/httputils/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/httputils/*.go -%dir %{gopath}/src/%{import_path}/pkg/iptables -%{gopath}/src/%{import_path}/pkg/iptables/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/iptables/*.go -%dir %{gopath}/src/%{import_path}/pkg/jsonlog -%{gopath}/src/%{import_path}/pkg/jsonlog/*.go -%dir %{gopath}/src/%{import_path}/pkg/listenbuffer -%{gopath}/src/%{import_path}/pkg/listenbuffer/*.go -%dir %{gopath}/src/%{import_path}/pkg/log -%{gopath}/src/%{import_path}/pkg/log/*.go -%dir %{gopath}/src/%{import_path}/pkg/mflag -%{gopath}/src/%{import_path}/pkg/mflag/LICENSE -%{gopath}/src/%{import_path}/pkg/mflag/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/mflag/README.md -%dir %{gopath}/src/%{import_path}/pkg/mflag/example -%{gopath}/src/%{import_path}/pkg/mflag/example/example.go -%{gopath}/src/%{import_path}/pkg/mflag/*.go -%dir %{gopath}/src/%{import_path}/pkg/mount -%{gopath}/src/%{import_path}/pkg/mount/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/mount/*.go -%dir %{gopath}/src/%{import_path}/pkg/namesgenerator -%{gopath}/src/%{import_path}/pkg/namesgenerator/*.go -%dir %{gopath}/src/%{import_path}/pkg/networkfs -%{gopath}/src/%{import_path}/pkg/networkfs/MAINTAINERS -%dir %{gopath}/src/%{import_path}/pkg/networkfs/etchosts -%{gopath}/src/%{import_path}/pkg/networkfs/etchosts/*.go -%dir %{gopath}/src/%{import_path}/pkg/networkfs/resolvconf -%{gopath}/src/%{import_path}/pkg/networkfs/resolvconf/*.go -%dir %{gopath}/src/%{import_path}/pkg/parsers -%{gopath}/src/%{import_path}/pkg/parsers/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/parsers/*.go -%dir %{gopath}/src/%{import_path}/pkg/parsers/filters -%{gopath}/src/%{import_path}/pkg/parsers/filters/*.go -%dir %{gopath}/src/%{import_path}/pkg/parsers/kernel -%{gopath}/src/%{import_path}/pkg/parsers/kernel/*.go -%dir %{gopath}/src/%{import_path}/pkg/parsers/operatingsystem -%{gopath}/src/%{import_path}/pkg/parsers/operatingsystem/*.go -%dir %{gopath}/src/%{import_path}/pkg/proxy -%{gopath}/src/%{import_path}/pkg/proxy/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/proxy/*.go -%dir %{gopath}/src/%{import_path}/pkg/signal -%{gopath}/src/%{import_path}/pkg/signal/*.go -%dir %{gopath}/src/%{import_path}/pkg/symlink -%{gopath}/src/%{import_path}/pkg/symlink/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/symlink/*.go -%dir %{gopath}/src/%{import_path}/pkg/symlink/testdata -%dir %{gopath}/src/%{import_path}/pkg/symlink/testdata/fs -%dir %{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/a -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/a/d -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/a/e -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/a/f -%dir %{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/b -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/b/h -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/g -%{gopath}/src/%{import_path}/pkg/symlink/testdata/fs/i -%dir %{gopath}/src/%{import_path}/pkg/sysinfo -%{gopath}/src/%{import_path}/pkg/sysinfo/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/sysinfo/*.go -%dir %{gopath}/src/%{import_path}/pkg/system -%{gopath}/src/%{import_path}/pkg/system/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/system/*.go -%dir %{gopath}/src/%{import_path}/pkg/systemd -%{gopath}/src/%{import_path}/pkg/systemd/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/systemd/*.go -%dir %{gopath}/src/%{import_path}/pkg/tailfile -%{gopath}/src/%{import_path}/pkg/tailfile/*.go -%dir %{gopath}/src/%{import_path}/pkg/tarsum -%{gopath}/src/%{import_path}/pkg/tarsum/*.go -%dir %{gopath}/src/%{import_path}/pkg/tarsum/testdata -%dir %{gopath}/src/%{import_path}/pkg/tarsum/testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457 -%{gopath}/src/%{import_path}/pkg/tarsum/testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json -%{gopath}/src/%{import_path}/pkg/tarsum/testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar -%dir %{gopath}/src/%{import_path}/pkg/tarsum/testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158 -%{gopath}/src/%{import_path}/pkg/tarsum/testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json -%{gopath}/src/%{import_path}/pkg/tarsum/testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar -%dir %{gopath}/src/%{import_path}/pkg/truncindex -%{gopath}/src/%{import_path}/pkg/truncindex/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/truncindex/*.go -%dir %{gopath}/src/%{import_path}/pkg/term -%{gopath}/src/%{import_path}/pkg/term/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/term/*.go -%dir %{gopath}/src/%{import_path}/pkg/testutils -%{gopath}/src/%{import_path}/pkg/testutils/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/testutils/README.md -%{gopath}/src/%{import_path}/pkg/testutils/utils.go -%dir %{gopath}/src/%{import_path}/pkg/units -%{gopath}/src/%{import_path}/pkg/units/MAINTAINERS -%{gopath}/src/%{import_path}/pkg/units/*.go -%dir %{gopath}/src/%{import_path}/pkg/version -%{gopath}/src/%{import_path}/pkg/version/*.go +%doc AUTHORS CHANGELOG.md CONTRIBUTING.md LICENSE MAINTAINERS NOTICE README.md +%{gopath}/src/%{common_path}/* %changelog -* Thu Nov 06 2014 Jim Perrin<jperrin@centos.org> - 1.2.0-1.8 -- Adjust build requirements -- Remove -H option from docker.sysconfig -- Comment out symlinks and other rhel-specific items in spec +* Fri Dec 05 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.2-4 +- update libcontainer paths +- update docker.sysconfig to include DOCKER_TMPDIR +- update docker.service unitfile +- package provides docker-io-devel + +* Mon Dec 01 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.2-3 +- revert docker.service change, -H fd:// in sysconfig file + +* Mon Dec 01 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.2-2 +- update systemd files + +* Tue Nov 25 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.2-1 +- Resolves: rhbz#1167870 - update to v1.3.2 +- Fixes CVE-2014-6407, CVE-2014-6408 + +* Fri Nov 14 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.1-2 +- remove unused buildrequires + +* Thu Nov 13 2014 Lokesh Mandvekar <lsm5@redhat.com> - 1.3.1-1 +- bump to upstream v1.3.1 +- patch to vendor in go-md2man and deps for manpage generation * Thu Oct 30 2014 Dan Walsh <dwalsh@redhat.com> - 1.2.0-1.8 - Remove docker-rhel entitlment patch. This was buggy and is no longer needed