From a2b5ed5c3de38693c4d877ae39fcd74d1846b619 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Dec 10 2014 11:17:28 +0000 Subject: import docker-1.3.2-4.el7 --- 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 +Date: Thu, 27 Nov 2014 23:55:03 +0200 +Subject: [PATCH 7/9] validate image ID properly & before load + +Signed-off-by: Cristian Staretu +--- + 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 +Date: Thu, 13 Nov 2014 11:24:09 -0800 +Subject: [PATCH] include vendor repos for manpage gen + +Signed-off-by: Lokesh Mandvekar +--- + 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: ++ ++* ++ ++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 `45`, which renders as ++ 45. ++ ++ ++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 . ++// 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: ++ // ++ //
++ // ... ++ //
++ 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
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") ++ 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
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("") ++ 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 . ++// 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", ++ "

Header 1

\n", ++ ++ "## Header 2\n", ++ "

Header 2

\n", ++ ++ "### Header 3\n", ++ "

Header 3

\n", ++ ++ "#### Header 4\n", ++ "

Header 4

\n", ++ ++ "##### Header 5\n", ++ "
Header 5
\n", ++ ++ "###### Header 6\n", ++ "
Header 6
\n", ++ ++ "####### Header 7\n", ++ "
# Header 7
\n", ++ ++ "#Header 1\n", ++ "

Header 1

\n", ++ ++ "##Header 2\n", ++ "

Header 2

\n", ++ ++ "###Header 3\n", ++ "

Header 3

\n", ++ ++ "####Header 4\n", ++ "

Header 4

\n", ++ ++ "#####Header 5\n", ++ "
Header 5
\n", ++ ++ "######Header 6\n", ++ "
Header 6
\n", ++ ++ "#######Header 7\n", ++ "
#Header 7
\n", ++ ++ "Hello\n# Header 1\nGoodbye\n", ++ "

Hello

\n\n

Header 1

\n\n

Goodbye

\n", ++ ++ "* List\n# Header\n* List\n", ++ "
    \n
  • List

    \n\n

    Header

  • \n\n
  • List

  • \n
\n", ++ ++ "* List\n#Header\n* List\n", ++ "
    \n
  • List

    \n\n

    Header

  • \n\n
  • List

  • \n
\n", ++ ++ "* List\n * Nested list\n # Nested header\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested list

      \n\n" + ++ "

      Nested header

    • \n
  • \n
\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestPrefixHeaderSpaceExtension(t *testing.T) { ++ var tests = []string{ ++ "# Header 1\n", ++ "

Header 1

\n", ++ ++ "## Header 2\n", ++ "

Header 2

\n", ++ ++ "### Header 3\n", ++ "

Header 3

\n", ++ ++ "#### Header 4\n", ++ "

Header 4

\n", ++ ++ "##### Header 5\n", ++ "
Header 5
\n", ++ ++ "###### Header 6\n", ++ "
Header 6
\n", ++ ++ "####### Header 7\n", ++ "

####### Header 7

\n", ++ ++ "#Header 1\n", ++ "

#Header 1

\n", ++ ++ "##Header 2\n", ++ "

##Header 2

\n", ++ ++ "###Header 3\n", ++ "

###Header 3

\n", ++ ++ "####Header 4\n", ++ "

####Header 4

\n", ++ ++ "#####Header 5\n", ++ "

#####Header 5

\n", ++ ++ "######Header 6\n", ++ "

######Header 6

\n", ++ ++ "#######Header 7\n", ++ "

#######Header 7

\n", ++ ++ "Hello\n# Header 1\nGoodbye\n", ++ "

Hello

\n\n

Header 1

\n\n

Goodbye

\n", ++ ++ "* List\n# Header\n* List\n", ++ "
    \n
  • List

    \n\n

    Header

  • \n\n
  • List

  • \n
\n", ++ ++ "* List\n#Header\n* List\n", ++ "
    \n
  • List\n#Header
  • \n
  • List
  • \n
\n", ++ ++ "* List\n * Nested list\n # Nested header\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested list

      \n\n" + ++ "

      Nested header

    • \n
  • \n
\n", ++ } ++ doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS) ++} ++ ++func TestPrefixHeaderIdExtension(t *testing.T) { ++ var tests = []string{ ++ "# Header 1 {#someid}\n", ++ "

Header 1

\n", ++ ++ "# Header 1 {#someid} \n", ++ "

Header 1

\n", ++ ++ "# Header 1 {#someid}\n", ++ "

Header 1

\n", ++ ++ "# Header 1 {#someid\n", ++ "

Header 1 {#someid

\n", ++ ++ "# Header 1 {#someid\n", ++ "

Header 1 {#someid

\n", ++ ++ "# Header 1 {#someid}}\n", ++ "

Header 1

\n\n

}

\n", ++ ++ "## Header 2 {#someid}\n", ++ "

Header 2

\n", ++ ++ "### Header 3 {#someid}\n", ++ "

Header 3

\n", ++ ++ "#### Header 4 {#someid}\n", ++ "

Header 4

\n", ++ ++ "##### Header 5 {#someid}\n", ++ "
Header 5
\n", ++ ++ "###### Header 6 {#someid}\n", ++ "
Header 6
\n", ++ ++ "####### Header 7 {#someid}\n", ++ "
# Header 7
\n", ++ ++ "# Header 1 # {#someid}\n", ++ "

Header 1

\n", ++ ++ "## Header 2 ## {#someid}\n", ++ "

Header 2

\n", ++ ++ "Hello\n# Header 1\nGoodbye\n", ++ "

Hello

\n\n

Header 1

\n\n

Goodbye

\n", ++ ++ "* List\n# Header {#someid}\n* List\n", ++ "
    \n
  • List

    \n\n

    Header

  • \n\n
  • List

  • \n
\n", ++ ++ "* List\n#Header {#someid}\n* List\n", ++ "
    \n
  • List

    \n\n

    Header

  • \n\n
  • List

  • \n
\n", ++ ++ "* List\n * Nested list\n # Nested header {#someid}\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested list

      \n\n" + ++ "

      Nested header

    • \n
  • \n
\n", ++ } ++ doTestsBlock(t, tests, EXTENSION_HEADER_IDS) ++} ++ ++func TestUnderlineHeaders(t *testing.T) { ++ var tests = []string{ ++ "Header 1\n========\n", ++ "

Header 1

\n", ++ ++ "Header 2\n--------\n", ++ "

Header 2

\n", ++ ++ "A\n=\n", ++ "

A

\n", ++ ++ "B\n-\n", ++ "

B

\n", ++ ++ "Paragraph\nHeader\n=\n", ++ "

Paragraph

\n\n

Header

\n", ++ ++ "Header\n===\nParagraph\n", ++ "

Header

\n\n

Paragraph

\n", ++ ++ "Header\n===\nAnother header\n---\n", ++ "

Header

\n\n

Another header

\n", ++ ++ " Header\n======\n", ++ "

Header

\n", ++ ++ " Code\n========\n", ++ "
Code\n
\n\n

========

\n", ++ ++ "Header with *inline*\n=====\n", ++ "

Header with inline

\n", ++ ++ "* List\n * Sublist\n Not a header\n ------\n", ++ "
    \n
  • List\n\n
      \n
    • Sublist\nNot a header\n------
    • \n
  • \n
\n", ++ ++ "Paragraph\n\n\n\n\nHeader\n===\n", ++ "

Paragraph

\n\n

Header

\n", ++ ++ "Trailing space \n==== \n\n", ++ "

Trailing space

\n", ++ ++ "Trailing spaces\n==== \n\n", ++ "

Trailing spaces

\n", ++ ++ "Double underline\n=====\n=====\n", ++ "

Double underline

\n\n

=====

\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestHorizontalRule(t *testing.T) { ++ var tests = []string{ ++ "-\n", ++ "

-

\n", ++ ++ "--\n", ++ "

--

\n", ++ ++ "---\n", ++ "
\n", ++ ++ "----\n", ++ "
\n", ++ ++ "*\n", ++ "

*

\n", ++ ++ "**\n", ++ "

**

\n", ++ ++ "***\n", ++ "
\n", ++ ++ "****\n", ++ "
\n", ++ ++ "_\n", ++ "

_

\n", ++ ++ "__\n", ++ "

__

\n", ++ ++ "___\n", ++ "
\n", ++ ++ "____\n", ++ "
\n", ++ ++ "-*-\n", ++ "

-*-

\n", ++ ++ "- - -\n", ++ "
\n", ++ ++ "* * *\n", ++ "
\n", ++ ++ "_ _ _\n", ++ "
\n", ++ ++ "-----*\n", ++ "

-----*

\n", ++ ++ " ------ \n", ++ "
\n", ++ ++ "Hello\n***\n", ++ "

Hello

\n\n
\n", ++ ++ "---\n***\n___\n", ++ "
\n\n
\n\n
\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestUnorderedList(t *testing.T) { ++ var tests = []string{ ++ "* Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "* Yin\n* Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "* Ting\n* Bong\n* Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "* Yin\n\n* Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "* Ting\n\n* Bong\n* Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "+ Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "+ Yin\n+ Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "+ Ting\n+ Bong\n+ Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "+ Yin\n\n+ Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "+ Ting\n\n+ Bong\n+ Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "- Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "- Yin\n- Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "- Ting\n- Bong\n- Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "- Yin\n\n- Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "- Ting\n\n- Bong\n- Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "*Hello\n", ++ "

*Hello

\n", ++ ++ "* Hello \n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "* Hello \n Next line \n", ++ "
    \n
  • Hello\nNext line
  • \n
\n", ++ ++ "Paragraph\n* No linebreak\n", ++ "

Paragraph\n* No linebreak

\n", ++ ++ "Paragraph\n\n* Linebreak\n", ++ "

Paragraph

\n\n
    \n
  • Linebreak
  • \n
\n", ++ ++ "* List\n * Nested list\n", ++ "
    \n
  • List\n\n
      \n
    • Nested list
    • \n
  • \n
\n", ++ ++ "* List\n\n * Nested list\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested list
    • \n
  • \n
\n", ++ ++ "* List\n Second line\n\n + Nested\n", ++ "
    \n
  • List\nSecond line

    \n\n
      \n
    • Nested
    • \n
  • \n
\n", ++ ++ "* List\n + Nested\n\n Continued\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested
    • \n
    \n\n

    Continued

  • \n
\n", ++ ++ "* List\n * shallow indent\n", ++ "
    \n
  • List\n\n
      \n
    • shallow indent
    • \n
  • \n
\n", ++ ++ "* List\n" + ++ " * shallow indent\n" + ++ " * part of second list\n" + ++ " * still second\n" + ++ " * almost there\n" + ++ " * third level\n", ++ "
    \n" + ++ "
  • List\n\n" + ++ "
      \n" + ++ "
    • shallow indent
    • \n" + ++ "
    • part of second list
    • \n" + ++ "
    • still second
    • \n" + ++ "
    • almost there\n\n" + ++ "
        \n" + ++ "
      • third level
      • \n" + ++ "
    • \n" + ++ "
  • \n" + ++ "
\n", ++ ++ "* List\n extra indent, same paragraph\n", ++ "
    \n
  • List\n extra indent, same paragraph
  • \n
\n", ++ ++ "* List\n\n code block\n", ++ "
    \n
  • List

    \n\n
    code block\n
  • \n
\n", ++ ++ "* List\n\n code block with spaces\n", ++ "
    \n
  • List

    \n\n
      code block with spaces\n
  • \n
\n", ++ ++ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n", ++ "
    \n
  • List

    \n\n
      \n
    • sublist
    • \n
    \n\n

    normal text

    \n\n
      \n
    • another sublist
    • \n
  • \n
\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestOrderedList(t *testing.T) { ++ var tests = []string{ ++ "1. Hello\n", ++ "
    \n
  1. Hello
  2. \n
\n", ++ ++ "1. Yin\n2. Yang\n", ++ "
    \n
  1. Yin
  2. \n
  3. Yang
  4. \n
\n", ++ ++ "1. Ting\n2. Bong\n3. Goo\n", ++ "
    \n
  1. Ting
  2. \n
  3. Bong
  4. \n
  5. Goo
  6. \n
\n", ++ ++ "1. Yin\n\n2. Yang\n", ++ "
    \n
  1. Yin

  2. \n\n
  3. Yang

  4. \n
\n", ++ ++ "1. Ting\n\n2. Bong\n3. Goo\n", ++ "
    \n
  1. Ting

  2. \n\n
  3. Bong

  4. \n\n
  5. Goo

  6. \n
\n", ++ ++ "1 Hello\n", ++ "

1 Hello

\n", ++ ++ "1.Hello\n", ++ "

1.Hello

\n", ++ ++ "1. Hello \n", ++ "
    \n
  1. Hello
  2. \n
\n", ++ ++ "1. Hello \n Next line \n", ++ "
    \n
  1. Hello\nNext line
  2. \n
\n", ++ ++ "Paragraph\n1. No linebreak\n", ++ "

Paragraph\n1. No linebreak

\n", ++ ++ "Paragraph\n\n1. Linebreak\n", ++ "

Paragraph

\n\n
    \n
  1. Linebreak
  2. \n
\n", ++ ++ "1. List\n 1. Nested list\n", ++ "
    \n
  1. List\n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", ++ ++ "1. List\n\n 1. Nested list\n", ++ "
    \n
  1. List

    \n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", ++ ++ "1. List\n Second line\n\n 1. Nested\n", ++ "
    \n
  1. List\nSecond line

    \n\n
      \n
    1. Nested
    2. \n
  2. \n
\n", ++ ++ "1. List\n 1. Nested\n\n Continued\n", ++ "
    \n
  1. List

    \n\n
      \n
    1. Nested
    2. \n
    \n\n

    Continued

  2. \n
\n", ++ ++ "1. List\n 1. shallow indent\n", ++ "
    \n
  1. List\n\n
      \n
    1. shallow indent
    2. \n
  2. \n
\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", ++ "
    \n" + ++ "
  1. List\n\n" + ++ "
      \n" + ++ "
    1. shallow indent
    2. \n" + ++ "
    3. part of second list
    4. \n" + ++ "
    5. still second
    6. \n" + ++ "
    7. almost there\n\n" + ++ "
        \n" + ++ "
      1. third level
      2. \n" + ++ "
    8. \n" + ++ "
  2. \n" + ++ "
\n", ++ ++ "1. List\n extra indent, same paragraph\n", ++ "
    \n
  1. List\n extra indent, same paragraph
  2. \n
\n", ++ ++ "1. List\n\n code block\n", ++ "
    \n
  1. List

    \n\n
    code block\n
  2. \n
\n", ++ ++ "1. List\n\n code block with spaces\n", ++ "
    \n
  1. List

    \n\n
      code block with spaces\n
  2. \n
\n", ++ ++ "1. List\n * Mixted list\n", ++ "
    \n
  1. List\n\n
      \n
    • Mixted list
    • \n
  2. \n
\n", ++ ++ "1. List\n * Mixed list\n", ++ "
    \n
  1. List\n\n
      \n
    • Mixed list
    • \n
  2. \n
\n", ++ ++ "* Start with unordered\n 1. Ordered\n", ++ "
    \n
  • Start with unordered\n\n
      \n
    1. Ordered
    2. \n
  • \n
\n", ++ ++ "* Start with unordered\n 1. Ordered\n", ++ "
    \n
  • Start with unordered\n\n
      \n
    1. Ordered
    2. \n
  • \n
\n", ++ ++ "1. numbers\n1. are ignored\n", ++ "
    \n
  1. numbers
  2. \n
  3. are ignored
  4. \n
\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestPreformattedHtml(t *testing.T) { ++ var tests = []string{ ++ "
\n", ++ "
\n", ++ ++ "
\n
\n", ++ "
\n
\n", ++ ++ "
\n
\nParagraph\n", ++ "

\n
\nParagraph

\n", ++ ++ "
\n
\n", ++ "
\n
\n", ++ ++ "
\nAnything here\n
\n", ++ "
\nAnything here\n
\n", ++ ++ "
\n Anything here\n
\n", ++ "
\n Anything here\n
\n", ++ ++ "
\nAnything here\n
\n", ++ "
\nAnything here\n
\n", ++ ++ "
\nThis is *not* &proceessed\n
\n", ++ "
\nThis is *not* &proceessed\n
\n", ++ ++ "\n Something\n\n", ++ "

\n Something\n

\n", ++ ++ "
\n Something here\n\n", ++ "

\n Something here\n

\n", ++ ++ "Paragraph\n
\nHere? >&<\n
\n", ++ "

Paragraph\n

\nHere? >&<\n

\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\n", ++ "

Paragraph

\n\n
\nHow about here? >&<\n
\n", ++ ++ "Paragraph\n
\nHere? >&<\n
\nAnd here?\n", ++ "

Paragraph\n

\nHere? >&<\n
\nAnd here?

\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\nAnd here?\n", ++ "

Paragraph

\n\n

\nHow about here? >&<\n
\nAnd here?

\n", ++ ++ "Paragraph\n
\nHere? >&<\n
\n\nAnd here?\n", ++ "

Paragraph\n

\nHere? >&<\n

\n\n

And here?

\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\n\nAnd here?\n", ++ "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\n", ++ } ++ doTestsBlock(t, tests, 0) ++} ++ ++func TestPreformattedHtmlLax(t *testing.T) { ++ var tests = []string{ ++ "Paragraph\n
\nHere? >&<\n
\n", ++ "

Paragraph

\n\n
\nHere? >&<\n
\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\n", ++ "

Paragraph

\n\n
\nHow about here? >&<\n
\n", ++ ++ "Paragraph\n
\nHere? >&<\n
\nAnd here?\n", ++ "

Paragraph

\n\n
\nHere? >&<\n
\n\n

And here?

\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\nAnd here?\n", ++ "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\n", ++ ++ "Paragraph\n
\nHere? >&<\n
\n\nAnd here?\n", ++ "

Paragraph

\n\n
\nHere? >&<\n
\n\n

And here?

\n", ++ ++ "Paragraph\n\n
\nHow about here? >&<\n
\n\nAnd here?\n", ++ "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\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", ++ "
func foo() bool {\n\treturn true;\n}\n
\n", ++ ++ "``` c\n/* special & char < > \" escaping */\n```\n", ++ "
/* special & char < > " escaping */\n
\n", ++ ++ "``` c\nno *inline* processing ~~of text~~\n```\n", ++ "
no *inline* processing ~~of text~~\n
\n", ++ ++ "```\nNo language\n```\n", ++ "
No language\n
\n", ++ ++ "``` {ocaml}\nlanguage in braces\n```\n", ++ "
language in braces\n
\n", ++ ++ "``` {ocaml} \nwith extra whitespace\n```\n", ++ "
with extra whitespace\n
\n", ++ ++ "```{ ocaml }\nwith extra whitespace\n```\n", ++ "
with extra whitespace\n
\n", ++ ++ "~ ~~ java\nWith whitespace\n~~~\n", ++ "

~ ~~ java\nWith whitespace\n~~~

\n", ++ ++ "~~\nonly two\n~~\n", ++ "

~~\nonly two\n~~

\n", ++ ++ "```` python\nextra\n````\n", ++ "
extra\n
\n", ++ ++ "~~~ perl\nthree to start, four to end\n~~~~\n", ++ "

~~~ perl\nthree to start, four to end\n~~~~

\n", ++ ++ "~~~~ perl\nfour to start, three to end\n~~~\n", ++ "

~~~~ perl\nfour to start, three to end\n~~~

\n", ++ ++ "~~~ bash\ntildes\n~~~\n", ++ "
tildes\n
\n", ++ ++ "``` lisp\nno ending\n", ++ "

``` lisp\nno ending

\n", ++ ++ "~~~ lisp\nend with language\n~~~ lisp\n", ++ "

~~~ lisp\nend with language\n~~~ lisp

\n", ++ ++ "```\nmismatched begin and end\n~~~\n", ++ "

```\nmismatched begin and end\n~~~

\n", ++ ++ "~~~\nmismatched begin and end\n```\n", ++ "

~~~\nmismatched begin and end\n```

\n", ++ ++ " ``` oz\nleading spaces\n```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ "``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
``` oz\n
\n\n

leading spaces\n ```

\n", ++ ++ "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n", ++ "

Bla bla

\n\n
code blocks breakup paragraphs\n
\n\n

Bla Bla

\n", ++ ++ "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nAnd some text after a fenced code block", ++ "

Some text before a fenced code block

\n\n
code blocks breakup paragraphs\n
\n\n

And some text after a fenced code block

\n", ++ ++ "`", ++ "

`

\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", ++ "

Bla bla

\n\n
code blocks breakup paragraphs\n
\n\n

Bla Bla

\n\n
multiple code blocks work okay\n
\n\n

Bla Bla

\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", ++ "

Some text before a fenced code block

\n\n
code blocks breakup paragraphs\n
\n\n

Some text in between

\n\n
multiple code blocks work okay\n
\n\n

And some text after a fenced code block

\n", ++ } ++ doTestsBlock(t, tests, EXTENSION_FENCED_CODE) ++} ++ ++func TestTable(t *testing.T) { ++ var tests = []string{ ++ "a | b\n---|---\nc | d\n", ++ "\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n
ab
cd
\n", ++ ++ "a | b\n---|--\nc | d\n", ++ "

a | b\n---|--\nc | d

\n", ++ ++ "|a|b|c|d|\n|----|----|----|---|\n|e|f|g|h|\n", ++ "\n\n\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n\n\n
abcd
efgh
\n", ++ ++ "*a*|__b__|[c](C)|d\n---|---|---|---\ne|f|g|h\n", ++ "\n\n\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n\n\n
abcd
efgh
\n", ++ ++ "a|b|c\n---|---|---\nd|e|f\ng|h\ni|j|k|l|m\nn|o|p\n", ++ "\n\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n
abc
def
gh
ijk
nop
\n", ++ ++ "a|b|c\n---|---|---\n*d*|__e__|f\n", ++ "\n\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n\n
abc
def
\n", ++ ++ "a|b|c|d\n:--|--:|:-:|---\ne|f|g|h\n", ++ "\n\n\n\n\n" + ++ "\n\n\n\n\n" + ++ "\n\n\n\n" + ++ "\n\n\n\n
abcd
efgh
\n", ++ ++ "a|b|c\n---|---|---\n", ++ "\n\n\n\n\n\n\n\n\n\n\n
abc
\n", ++ ++ "a| b|c | d | e\n---|---|---|---|---\nf| g|h | i |j\n", ++ "\n\n\n\n\n\n\n\n\n\n\n" + ++ "\n\n\n\n\n\n\n\n\n
abcde
fghij
\n", ++ ++ "a|b\\|c|d\n---|---|---\nf|g\\|h|i\n", ++ "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab|cd
fg|hi
\n", ++ } ++ doTestsBlock(t, tests, EXTENSION_TABLES) ++} ++ ++func TestUnorderedListWith_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) { ++ var tests = []string{ ++ "* Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "* Yin\n* Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "* Ting\n* Bong\n* Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "* Yin\n\n* Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "* Ting\n\n* Bong\n* Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "+ Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "+ Yin\n+ Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "+ Ting\n+ Bong\n+ Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "+ Yin\n\n+ Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "+ Ting\n\n+ Bong\n+ Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "- Hello\n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "- Yin\n- Yang\n", ++ "
    \n
  • Yin
  • \n
  • Yang
  • \n
\n", ++ ++ "- Ting\n- Bong\n- Goo\n", ++ "
    \n
  • Ting
  • \n
  • Bong
  • \n
  • Goo
  • \n
\n", ++ ++ "- Yin\n\n- Yang\n", ++ "
    \n
  • Yin

  • \n\n
  • Yang

  • \n
\n", ++ ++ "- Ting\n\n- Bong\n- Goo\n", ++ "
    \n
  • Ting

  • \n\n
  • Bong

  • \n\n
  • Goo

  • \n
\n", ++ ++ "*Hello\n", ++ "

*Hello

\n", ++ ++ "* Hello \n", ++ "
    \n
  • Hello
  • \n
\n", ++ ++ "* Hello \n Next line \n", ++ "
    \n
  • Hello\nNext line
  • \n
\n", ++ ++ "Paragraph\n* No linebreak\n", ++ "

Paragraph

\n\n
    \n
  • No linebreak
  • \n
\n", ++ ++ "Paragraph\n\n* Linebreak\n", ++ "

Paragraph

\n\n
    \n
  • Linebreak
  • \n
\n", ++ ++ "* List\n * Nested list\n", ++ "
    \n
  • List\n\n
      \n
    • Nested list
    • \n
  • \n
\n", ++ ++ "* List\n\n * Nested list\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested list
    • \n
  • \n
\n", ++ ++ "* List\n Second line\n\n + Nested\n", ++ "
    \n
  • List\nSecond line

    \n\n
      \n
    • Nested
    • \n
  • \n
\n", ++ ++ "* List\n + Nested\n\n Continued\n", ++ "
    \n
  • List

    \n\n
      \n
    • Nested
    • \n
    \n\n

    Continued

  • \n
\n", ++ ++ "* List\n * shallow indent\n", ++ "
    \n
  • List\n\n
      \n
    • shallow indent
    • \n
  • \n
\n", ++ ++ "* List\n" + ++ " * shallow indent\n" + ++ " * part of second list\n" + ++ " * still second\n" + ++ " * almost there\n" + ++ " * third level\n", ++ "
    \n" + ++ "
  • List\n\n" + ++ "
      \n" + ++ "
    • shallow indent
    • \n" + ++ "
    • part of second list
    • \n" + ++ "
    • still second
    • \n" + ++ "
    • almost there\n\n" + ++ "
        \n" + ++ "
      • third level
      • \n" + ++ "
    • \n" + ++ "
  • \n" + ++ "
\n", ++ ++ "* List\n extra indent, same paragraph\n", ++ "
    \n
  • List\n extra indent, same paragraph
  • \n
\n", ++ ++ "* List\n\n code block\n", ++ "
    \n
  • List

    \n\n
    code block\n
  • \n
\n", ++ ++ "* List\n\n code block with spaces\n", ++ "
    \n
  • List

    \n\n
      code block with spaces\n
  • \n
\n", ++ ++ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n", ++ "
    \n
  • List

    \n\n
      \n
    • sublist
    • \n
    \n\n

    normal text

    \n\n
      \n
    • another sublist
    • \n
  • \n
\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", ++ "
    \n
  1. Hello
  2. \n
\n", ++ ++ "1. Yin\n2. Yang\n", ++ "
    \n
  1. Yin
  2. \n
  3. Yang
  4. \n
\n", ++ ++ "1. Ting\n2. Bong\n3. Goo\n", ++ "
    \n
  1. Ting
  2. \n
  3. Bong
  4. \n
  5. Goo
  6. \n
\n", ++ ++ "1. Yin\n\n2. Yang\n", ++ "
    \n
  1. Yin

  2. \n\n
  3. Yang

  4. \n
\n", ++ ++ "1. Ting\n\n2. Bong\n3. Goo\n", ++ "
    \n
  1. Ting

  2. \n\n
  3. Bong

  4. \n\n
  5. Goo

  6. \n
\n", ++ ++ "1 Hello\n", ++ "

1 Hello

\n", ++ ++ "1.Hello\n", ++ "

1.Hello

\n", ++ ++ "1. Hello \n", ++ "
    \n
  1. Hello
  2. \n
\n", ++ ++ "1. Hello \n Next line \n", ++ "
    \n
  1. Hello\nNext line
  2. \n
\n", ++ ++ "Paragraph\n1. No linebreak\n", ++ "

Paragraph

\n\n
    \n
  1. No linebreak
  2. \n
\n", ++ ++ "Paragraph\n\n1. Linebreak\n", ++ "

Paragraph

\n\n
    \n
  1. Linebreak
  2. \n
\n", ++ ++ "1. List\n 1. Nested list\n", ++ "
    \n
  1. List\n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", ++ ++ "1. List\n\n 1. Nested list\n", ++ "
    \n
  1. List

    \n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", ++ ++ "1. List\n Second line\n\n 1. Nested\n", ++ "
    \n
  1. List\nSecond line

    \n\n
      \n
    1. Nested
    2. \n
  2. \n
\n", ++ ++ "1. List\n 1. Nested\n\n Continued\n", ++ "
    \n
  1. List

    \n\n
      \n
    1. Nested
    2. \n
    \n\n

    Continued

  2. \n
\n", ++ ++ "1. List\n 1. shallow indent\n", ++ "
    \n
  1. List\n\n
      \n
    1. shallow indent
    2. \n
  2. \n
\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", ++ "
    \n" + ++ "
  1. List\n\n" + ++ "
      \n" + ++ "
    1. shallow indent
    2. \n" + ++ "
    3. part of second list
    4. \n" + ++ "
    5. still second
    6. \n" + ++ "
    7. almost there\n\n" + ++ "
        \n" + ++ "
      1. third level
      2. \n" + ++ "
    8. \n" + ++ "
  2. \n" + ++ "
\n", ++ ++ "1. List\n extra indent, same paragraph\n", ++ "
    \n
  1. List\n extra indent, same paragraph
  2. \n
\n", ++ ++ "1. List\n\n code block\n", ++ "
    \n
  1. List

    \n\n
    code block\n
  2. \n
\n", ++ ++ "1. List\n\n code block with spaces\n", ++ "
    \n
  1. List

    \n\n
      code block with spaces\n
  2. \n
\n", ++ ++ "1. List\n * Mixted list\n", ++ "
    \n
  1. List\n\n
      \n
    • Mixted list
    • \n
  2. \n
\n", ++ ++ "1. List\n * Mixed list\n", ++ "
    \n
  1. List\n\n
      \n
    • Mixed list
    • \n
  2. \n
\n", ++ ++ "* Start with unordered\n 1. Ordered\n", ++ "
    \n
  • Start with unordered\n\n
      \n
    1. Ordered
    2. \n
  • \n
\n", ++ ++ "* Start with unordered\n 1. Ordered\n", ++ "
    \n
  • Start with unordered\n\n
      \n
    1. Ordered
    2. \n
  • \n
\n", ++ ++ "1. numbers\n1. are ignored\n", ++ "
    \n
  1. numbers
  2. \n
  3. are ignored
  4. \n
\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", ++ "
func foo() bool {\n\treturn true;\n}\n
\n", ++ ++ "``` c\n/* special & char < > \" escaping */\n```\n", ++ "
/* special & char < > " escaping */\n
\n", ++ ++ "``` c\nno *inline* processing ~~of text~~\n```\n", ++ "
no *inline* processing ~~of text~~\n
\n", ++ ++ "```\nNo language\n```\n", ++ "
No language\n
\n", ++ ++ "``` {ocaml}\nlanguage in braces\n```\n", ++ "
language in braces\n
\n", ++ ++ "``` {ocaml} \nwith extra whitespace\n```\n", ++ "
with extra whitespace\n
\n", ++ ++ "```{ ocaml }\nwith extra whitespace\n```\n", ++ "
with extra whitespace\n
\n", ++ ++ "~ ~~ java\nWith whitespace\n~~~\n", ++ "

~ ~~ java\nWith whitespace\n~~~

\n", ++ ++ "~~\nonly two\n~~\n", ++ "

~~\nonly two\n~~

\n", ++ ++ "```` python\nextra\n````\n", ++ "
extra\n
\n", ++ ++ "~~~ perl\nthree to start, four to end\n~~~~\n", ++ "

~~~ perl\nthree to start, four to end\n~~~~

\n", ++ ++ "~~~~ perl\nfour to start, three to end\n~~~\n", ++ "

~~~~ perl\nfour to start, three to end\n~~~

\n", ++ ++ "~~~ bash\ntildes\n~~~\n", ++ "
tildes\n
\n", ++ ++ "``` lisp\nno ending\n", ++ "

``` lisp\nno ending

\n", ++ ++ "~~~ lisp\nend with language\n~~~ lisp\n", ++ "

~~~ lisp\nend with language\n~~~ lisp

\n", ++ ++ "```\nmismatched begin and end\n~~~\n", ++ "

```\nmismatched begin and end\n~~~

\n", ++ ++ "~~~\nmismatched begin and end\n```\n", ++ "

~~~\nmismatched begin and end\n```

\n", ++ ++ " ``` oz\nleading spaces\n```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ "``` oz\nleading spaces\n ```\n", ++ "
leading spaces\n
\n", ++ ++ " ``` oz\nleading spaces\n ```\n", ++ "
``` oz\n
\n\n

leading spaces

\n\n
```\n
\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", ++ "

" + ++ "Some title\n" + ++ "Another title line\n" + ++ "Yep, more here too\n" + ++ "

", ++ } ++ ++ 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 . ++// 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 \n", ++ "

zz <style>p {}</style>

\n", ++ ++ "zz \n", ++ "

zz <style>p {}</style>

\n", ++ ++ "\n", ++ "

<script>alert()</script>

\n", ++ ++ "zz \n", ++ "

zz <script>alert()</script>

\n", ++ ++ "zz \n", ++ "

zz <script>alert()</script>

\n", ++ ++ " \n", ++ "

<script>alert()</script>

\n", ++ ++ "\n", ++ "<script>alert()</script>\n", ++ ++ "\n", ++ "<script src='foo'></script>\n", ++ ++ "\n", ++ "<script src='a>b'></script>\n", ++ ++ "zz \n", ++ "

zz <script src='foo'></script>

\n", ++ ++ "zz \n", ++ "

zz <script src=foo></script>

\n", ++ ++ ``, ++ "<script><script src="http://example.com/exploit.js"></script></script>\n", ++ ++ `'';!--"=&{()}`, ++ "

'';!--"<xss>=&{()}

\n", ++ ++ "", ++ "

<script SRC=http://ha.ckers.org/xss.js></script>

\n", ++ ++ "", ++ "

<script \nSRC=http://ha.ckers.org/xss.js></script>

\n", ++ ++ ``, ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ `xss link`, ++ "

xss link

\n", ++ ++ "xss link", ++ "

xss link

\n", ++ ++ `">`, ++ "

<script>alert("XSS")</script>">

\n", ++ ++ "", ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ "", ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

\n", ++ ++ ``, ++ "

<script/XSS SRC="http://ha.ckers.org/xss.js"></script>

\n", ++ ++ "", ++ "

<body onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert("XSS")>

\n", ++ ++ ``, ++ "

<script/SRC="http://ha.ckers.org/xss.js"></script>

\n", ++ ++ `<`, ++ "

<<script>alert("XSS");//<</script>

\n", ++ ++ "