diff --git a/.docker.metadata b/.docker.metadata index a7675d7..bd853e6 100644 --- a/.docker.metadata +++ b/.docker.metadata @@ -1,7 +1,4 @@ -ea6af872200a1b7b6b371b1b3a47dcf38bb3cc4f SOURCES/011a826ff8b35f1d206a3de6f37fdb0292c948c9.tar.gz -14e8c28533777782d48a97a5c41f75cc645251ac SOURCES/446ad9bd9e8ec218aff5b22529c0bdc6df69d0e2.tar.gz -1a00c6b67a8b874cdbfc5d5a73c9d8775bb2f332 SOURCES/54a154d8b251df5e4788570dac4bea3cfa70b199.tar.gz +511dc35272b3949eb48a5dd5115c06e29bbcbdb9 SOURCES/bb472f05c975b343fb13e55325a985f4ac1d0ca2.tar.gz 18870c5eeee96c30dca0812c1ad4fd469595cbd6 SOURCES/dab51acd1b1a77f7cb01a1b7e2129ec85c846b71.tar.gz -062f6b3918b31da158c58d4f288de85351eb1124 SOURCES/docker-selinux-6267b83.tar.gz -1c2605ad4e26953f5d63fc2531c26fa47f71ddcf SOURCES/docker-storage-setup-d3b9ba7.tar.gz -9df03f0e64167be9fabe113c99297a4a8774f4fb SOURCES/websocket_client-0.32.0.tar.gz +b267c131454bcbf2c752c065fcadcfd4f7462c35 SOURCES/docker-selinux-44abd21.tar.gz +e3a90d52c646cd099d668efa2075f92314609498 SOURCES/docker-storage-setup-6898d43.tar.gz diff --git a/.gitignore b/.gitignore index 07759ee..8c8339a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,4 @@ -SOURCES/011a826ff8b35f1d206a3de6f37fdb0292c948c9.tar.gz -SOURCES/446ad9bd9e8ec218aff5b22529c0bdc6df69d0e2.tar.gz -SOURCES/54a154d8b251df5e4788570dac4bea3cfa70b199.tar.gz +SOURCES/bb472f05c975b343fb13e55325a985f4ac1d0ca2.tar.gz SOURCES/dab51acd1b1a77f7cb01a1b7e2129ec85c846b71.tar.gz -SOURCES/docker-selinux-6267b83.tar.gz -SOURCES/docker-storage-setup-d3b9ba7.tar.gz -SOURCES/websocket_client-0.32.0.tar.gz +SOURCES/docker-selinux-44abd21.tar.gz +SOURCES/docker-storage-setup-6898d43.tar.gz diff --git a/SOURCES/0001-Rework-patch-for-rhbz-1194445.patch b/SOURCES/0001-Rework-patch-for-rhbz-1194445.patch deleted file mode 100644 index 4c9aebb..0000000 --- a/SOURCES/0001-Rework-patch-for-rhbz-1194445.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 5e24a5214db77a021ab12faea417e5f6f6ab57ba Mon Sep 17 00:00:00 2001 -From: Lokesh Mandvekar <lsm5@fedoraproject.org> -Date: Mon, 20 Jul 2015 14:56:35 -0400 -Subject: [PATCH] Rework patch for rhbz#1194445 - -- make docker-py work well with older python-requests - -Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> ---- - docker/clientbase.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/docker/clientbase.py b/docker/clientbase.py -index c81ee0c..fd861bc 100644 ---- a/docker/clientbase.py -+++ b/docker/clientbase.py -@@ -166,7 +166,7 @@ class ClientBase(requests.Session): - """Generator for data coming from a chunked-encoded HTTP response.""" - if response.raw._fp.chunked: - reader = response.raw -- while not reader.closed: -+ while not reader._fp.isclosed(): - # this read call will block until we get a chunk - data = reader.read(1) - if not data: --- -1.8.3.1 - diff --git a/SOURCES/0001-atomic.sysconfig-use-rhel-tools-as-the-TOOLSIMG.patch b/SOURCES/0001-atomic.sysconfig-use-rhel-tools-as-the-TOOLSIMG.patch deleted file mode 100644 index a1c5c48..0000000 --- a/SOURCES/0001-atomic.sysconfig-use-rhel-tools-as-the-TOOLSIMG.patch +++ /dev/null @@ -1,24 +0,0 @@ -From d7e19069a5a4b7ae97b938e109a282d025023fb3 Mon Sep 17 00:00:00 2001 -From: Jonathan Lebon <jlebon@redhat.com> -Date: Fri, 17 Jul 2015 15:28:03 -0400 -Subject: [PATCH] atomic.sysconfig: use rhel-tools as the TOOLSIMG - -Related: https://github.com/projectatomic/atomic/pull/94 - ---- - atomic.sysconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/atomic.sysconfig b/atomic.sysconfig -index 8926e1c..36982f3 100644 ---- a/atomic.sysconfig -+++ b/atomic.sysconfig -@@ -2,4 +2,4 @@ - # A missing command on an atomic host platform will execute - # atomic run ${TOOLSIMG} COMMAND - # If the TOOLSIMG is defined --# export TOOLSIMG= -+# export TOOLSIMG=rhel7/rhel-tools --- -2.1.0 - diff --git a/SOURCES/codegangsta-cli.patch b/SOURCES/codegangsta-cli.patch deleted file mode 100644 index efa62a4..0000000 --- a/SOURCES/codegangsta-cli.patch +++ /dev/null @@ -1,2359 +0,0 @@ -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/app.go docker-1/vendor/src/github.com/codegangsta/cli/app.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/app.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/app.go 2015-01-16 03:56:49.105152140 -0500 -@@ -0,0 +1,248 @@ -+package cli -+ -+import ( -+ "fmt" -+ "io/ioutil" -+ "os" -+ "time" -+) -+ -+// App is the main structure of a cli application. It is recomended that -+// and app be created with the cli.NewApp() function -+type App struct { -+ // The name of the program. Defaults to os.Args[0] -+ Name string -+ // Description of the program. -+ Usage string -+ // Version of the program -+ Version string -+ // List of commands to execute -+ Commands []Command -+ // List of flags to parse -+ Flags []Flag -+ // Boolean to enable bash completion commands -+ EnableBashCompletion bool -+ // Boolean to hide built-in help command -+ HideHelp bool -+ // An action to execute when the bash-completion flag is set -+ BashComplete func(context *Context) -+ // An action to execute before any subcommands are run, but after the context is ready -+ // If a non-nil error is returned, no subcommands are run -+ Before func(context *Context) error -+ // The action to execute when no subcommands are specified -+ Action func(context *Context) -+ // Execute this function if the proper command cannot be found -+ CommandNotFound func(context *Context, command string) -+ // Compilation date -+ Compiled time.Time -+ // Author -+ Author string -+ // Author e-mail -+ Email string -+} -+ -+// Tries to find out when this binary was compiled. -+// Returns the current time if it fails to find it. -+func compileTime() time.Time { -+ info, err := os.Stat(os.Args[0]) -+ if err != nil { -+ return time.Now() -+ } -+ return info.ModTime() -+} -+ -+// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. -+func NewApp() *App { -+ return &App{ -+ Name: os.Args[0], -+ Usage: "A new cli application", -+ Version: "0.0.0", -+ BashComplete: DefaultAppComplete, -+ Action: helpCommand.Action, -+ Compiled: compileTime(), -+ Author: "Author", -+ Email: "unknown@email", -+ } -+} -+ -+// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination -+func (a *App) Run(arguments []string) error { -+ // append help to commands -+ if a.Command(helpCommand.Name) == nil && !a.HideHelp { -+ a.Commands = append(a.Commands, helpCommand) -+ a.appendFlag(HelpFlag) -+ } -+ -+ //append version/help flags -+ if a.EnableBashCompletion { -+ a.appendFlag(BashCompletionFlag) -+ } -+ a.appendFlag(VersionFlag) -+ -+ // parse flags -+ set := flagSet(a.Name, a.Flags) -+ set.SetOutput(ioutil.Discard) -+ err := set.Parse(arguments[1:]) -+ nerr := normalizeFlags(a.Flags, set) -+ if nerr != nil { -+ fmt.Println(nerr) -+ context := NewContext(a, set, set) -+ ShowAppHelp(context) -+ fmt.Println("") -+ return nerr -+ } -+ context := NewContext(a, set, set) -+ -+ if err != nil { -+ fmt.Printf("Incorrect Usage.\n\n") -+ ShowAppHelp(context) -+ fmt.Println("") -+ return err -+ } -+ -+ if checkCompletions(context) { -+ return nil -+ } -+ -+ if checkHelp(context) { -+ return nil -+ } -+ -+ if checkVersion(context) { -+ return nil -+ } -+ -+ if a.Before != nil { -+ err := a.Before(context) -+ if err != nil { -+ return err -+ } -+ } -+ -+ args := context.Args() -+ if args.Present() { -+ name := args.First() -+ c := a.Command(name) -+ if c != nil { -+ return c.Run(context) -+ } -+ } -+ -+ // Run default Action -+ a.Action(context) -+ return nil -+} -+ -+// Another entry point to the cli app, takes care of passing arguments and error handling -+func (a *App) RunAndExitOnError() { -+ if err := a.Run(os.Args); err != nil { -+ os.Stderr.WriteString(fmt.Sprintln(err)) -+ os.Exit(1) -+ } -+} -+ -+// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags -+func (a *App) RunAsSubcommand(ctx *Context) error { -+ // append help to commands -+ if len(a.Commands) > 0 { -+ if a.Command(helpCommand.Name) == nil && !a.HideHelp { -+ a.Commands = append(a.Commands, helpCommand) -+ a.appendFlag(HelpFlag) -+ } -+ } -+ -+ // append flags -+ if a.EnableBashCompletion { -+ a.appendFlag(BashCompletionFlag) -+ } -+ -+ // parse flags -+ set := flagSet(a.Name, a.Flags) -+ set.SetOutput(ioutil.Discard) -+ err := set.Parse(ctx.Args().Tail()) -+ nerr := normalizeFlags(a.Flags, set) -+ context := NewContext(a, set, ctx.globalSet) -+ -+ if nerr != nil { -+ fmt.Println(nerr) -+ if len(a.Commands) > 0 { -+ ShowSubcommandHelp(context) -+ } else { -+ ShowCommandHelp(ctx, context.Args().First()) -+ } -+ fmt.Println("") -+ return nerr -+ } -+ -+ if err != nil { -+ fmt.Printf("Incorrect Usage.\n\n") -+ ShowSubcommandHelp(context) -+ return err -+ } -+ -+ if checkCompletions(context) { -+ return nil -+ } -+ -+ if len(a.Commands) > 0 { -+ if checkSubcommandHelp(context) { -+ return nil -+ } -+ } else { -+ if checkCommandHelp(ctx, context.Args().First()) { -+ return nil -+ } -+ } -+ -+ if a.Before != nil { -+ err := a.Before(context) -+ if err != nil { -+ return err -+ } -+ } -+ -+ args := context.Args() -+ if args.Present() { -+ name := args.First() -+ c := a.Command(name) -+ if c != nil { -+ return c.Run(context) -+ } -+ } -+ -+ // Run default Action -+ if len(a.Commands) > 0 { -+ a.Action(context) -+ } else { -+ a.Action(ctx) -+ } -+ -+ return nil -+} -+ -+// Returns the named command on App. Returns nil if the command does not exist -+func (a *App) Command(name string) *Command { -+ for _, c := range a.Commands { -+ if c.HasName(name) { -+ return &c -+ } -+ } -+ -+ return nil -+} -+ -+func (a *App) hasFlag(flag Flag) bool { -+ for _, f := range a.Flags { -+ if flag == f { -+ return true -+ } -+ } -+ -+ return false -+} -+ -+func (a *App) appendFlag(flag Flag) { -+ if !a.hasFlag(flag) { -+ a.Flags = append(a.Flags, flag) -+ } -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/app_test.go docker-1/vendor/src/github.com/codegangsta/cli/app_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/app_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/app_test.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,399 @@ -+package cli_test -+ -+import ( -+ "fmt" -+ "os" -+ "testing" -+ -+ "github.com/codegangsta/cli" -+) -+ -+func ExampleApp() { -+ // set args for examples sake -+ os.Args = []string{"greet", "--name", "Jeremy"} -+ -+ app := cli.NewApp() -+ app.Name = "greet" -+ app.Flags = []cli.Flag{ -+ cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, -+ } -+ app.Action = func(c *cli.Context) { -+ fmt.Printf("Hello %v\n", c.String("name")) -+ } -+ app.Run(os.Args) -+ // Output: -+ // Hello Jeremy -+} -+ -+func ExampleAppSubcommand() { -+ // set args for examples sake -+ os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} -+ app := cli.NewApp() -+ app.Name = "say" -+ app.Commands = []cli.Command{ -+ { -+ Name: "hello", -+ ShortName: "hi", -+ Usage: "use it to see a description", -+ Description: "This is how we describe hello the function", -+ Subcommands: []cli.Command{ -+ { -+ Name: "english", -+ ShortName: "en", -+ Usage: "sends a greeting in english", -+ Description: "greets someone in english", -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "name", Value: "Bob", Usage: "Name of the person to greet"}, -+ }, -+ Action: func(c *cli.Context) { -+ fmt.Println("Hello,", c.String("name")) -+ }, -+ }, -+ }, -+ }, -+ } -+ -+ app.Run(os.Args) -+ // Output: -+ // Hello, Jeremy -+} -+ -+func ExampleAppHelp() { -+ // set args for examples sake -+ os.Args = []string{"greet", "h", "describeit"} -+ -+ app := cli.NewApp() -+ app.Name = "greet" -+ app.Flags = []cli.Flag{ -+ cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, -+ } -+ app.Commands = []cli.Command{ -+ { -+ Name: "describeit", -+ ShortName: "d", -+ Usage: "use it to see a description", -+ Description: "This is how we describe describeit the function", -+ Action: func(c *cli.Context) { -+ fmt.Printf("i like to describe things") -+ }, -+ }, -+ } -+ app.Run(os.Args) -+ // Output: -+ // NAME: -+ // describeit - use it to see a description -+ // -+ // USAGE: -+ // command describeit [arguments...] -+ // -+ // DESCRIPTION: -+ // This is how we describe describeit the function -+} -+ -+func ExampleAppBashComplete() { -+ // set args for examples sake -+ os.Args = []string{"greet", "--generate-bash-completion"} -+ -+ app := cli.NewApp() -+ app.Name = "greet" -+ app.EnableBashCompletion = true -+ app.Commands = []cli.Command{ -+ { -+ Name: "describeit", -+ ShortName: "d", -+ Usage: "use it to see a description", -+ Description: "This is how we describe describeit the function", -+ Action: func(c *cli.Context) { -+ fmt.Printf("i like to describe things") -+ }, -+ }, { -+ Name: "next", -+ Usage: "next example", -+ Description: "more stuff to see when generating bash completion", -+ Action: func(c *cli.Context) { -+ fmt.Printf("the next example") -+ }, -+ }, -+ } -+ -+ app.Run(os.Args) -+ // Output: -+ // describeit -+ // d -+ // next -+ // help -+ // h -+} -+ -+func TestApp_Run(t *testing.T) { -+ s := "" -+ -+ app := cli.NewApp() -+ app.Action = func(c *cli.Context) { -+ s = s + c.Args().First() -+ } -+ -+ err := app.Run([]string{"command", "foo"}) -+ expect(t, err, nil) -+ err = app.Run([]string{"command", "bar"}) -+ expect(t, err, nil) -+ expect(t, s, "foobar") -+} -+ -+var commandAppTests = []struct { -+ name string -+ expected bool -+}{ -+ {"foobar", true}, -+ {"batbaz", true}, -+ {"b", true}, -+ {"f", true}, -+ {"bat", false}, -+ {"nothing", false}, -+} -+ -+func TestApp_Command(t *testing.T) { -+ app := cli.NewApp() -+ fooCommand := cli.Command{Name: "foobar", ShortName: "f"} -+ batCommand := cli.Command{Name: "batbaz", ShortName: "b"} -+ app.Commands = []cli.Command{ -+ fooCommand, -+ batCommand, -+ } -+ -+ for _, test := range commandAppTests { -+ expect(t, app.Command(test.name) != nil, test.expected) -+ } -+} -+ -+func TestApp_CommandWithArgBeforeFlags(t *testing.T) { -+ var parsedOption, firstArg string -+ -+ app := cli.NewApp() -+ command := cli.Command{ -+ Name: "cmd", -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "option", Value: "", Usage: "some option"}, -+ }, -+ Action: func(c *cli.Context) { -+ parsedOption = c.String("option") -+ firstArg = c.Args().First() -+ }, -+ } -+ app.Commands = []cli.Command{command} -+ -+ app.Run([]string{"", "cmd", "my-arg", "--option", "my-option"}) -+ -+ expect(t, parsedOption, "my-option") -+ expect(t, firstArg, "my-arg") -+} -+ -+func TestApp_Float64Flag(t *testing.T) { -+ var meters float64 -+ -+ app := cli.NewApp() -+ app.Flags = []cli.Flag{ -+ cli.Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, -+ } -+ app.Action = func(c *cli.Context) { -+ meters = c.Float64("height") -+ } -+ -+ app.Run([]string{"", "--height", "1.93"}) -+ expect(t, meters, 1.93) -+} -+ -+func TestApp_ParseSliceFlags(t *testing.T) { -+ var parsedOption, firstArg string -+ var parsedIntSlice []int -+ var parsedStringSlice []string -+ -+ app := cli.NewApp() -+ command := cli.Command{ -+ Name: "cmd", -+ Flags: []cli.Flag{ -+ cli.IntSliceFlag{Name: "p", Value: &cli.IntSlice{}, Usage: "set one or more ip addr"}, -+ cli.StringSliceFlag{Name: "ip", Value: &cli.StringSlice{}, Usage: "set one or more ports to open"}, -+ }, -+ Action: func(c *cli.Context) { -+ parsedIntSlice = c.IntSlice("p") -+ parsedStringSlice = c.StringSlice("ip") -+ parsedOption = c.String("option") -+ firstArg = c.Args().First() -+ }, -+ } -+ app.Commands = []cli.Command{command} -+ -+ app.Run([]string{"", "cmd", "my-arg", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4"}) -+ -+ IntsEquals := func(a, b []int) bool { -+ if len(a) != len(b) { -+ return false -+ } -+ for i, v := range a { -+ if v != b[i] { -+ return false -+ } -+ } -+ return true -+ } -+ -+ StrsEquals := func(a, b []string) bool { -+ if len(a) != len(b) { -+ return false -+ } -+ for i, v := range a { -+ if v != b[i] { -+ return false -+ } -+ } -+ return true -+ } -+ var expectedIntSlice = []int{22, 80} -+ var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} -+ -+ if !IntsEquals(parsedIntSlice, expectedIntSlice) { -+ t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) -+ } -+ -+ if !StrsEquals(parsedStringSlice, expectedStringSlice) { -+ t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) -+ } -+} -+ -+func TestApp_BeforeFunc(t *testing.T) { -+ beforeRun, subcommandRun := false, false -+ beforeError := fmt.Errorf("fail") -+ var err error -+ -+ app := cli.NewApp() -+ -+ app.Before = func(c *cli.Context) error { -+ beforeRun = true -+ s := c.String("opt") -+ if s == "fail" { -+ return beforeError -+ } -+ -+ return nil -+ } -+ -+ app.Commands = []cli.Command{ -+ cli.Command{ -+ Name: "sub", -+ Action: func(c *cli.Context) { -+ subcommandRun = true -+ }, -+ }, -+ } -+ -+ app.Flags = []cli.Flag{ -+ cli.StringFlag{Name: "opt"}, -+ } -+ -+ // run with the Before() func succeeding -+ err = app.Run([]string{"command", "--opt", "succeed", "sub"}) -+ -+ if err != nil { -+ t.Fatalf("Run error: %s", err) -+ } -+ -+ if beforeRun == false { -+ t.Errorf("Before() not executed when expected") -+ } -+ -+ if subcommandRun == false { -+ t.Errorf("Subcommand not executed when expected") -+ } -+ -+ // reset -+ beforeRun, subcommandRun = false, false -+ -+ // run with the Before() func failing -+ err = app.Run([]string{"command", "--opt", "fail", "sub"}) -+ -+ // should be the same error produced by the Before func -+ if err != beforeError { -+ t.Errorf("Run error expected, but not received") -+ } -+ -+ if beforeRun == false { -+ t.Errorf("Before() not executed when expected") -+ } -+ -+ if subcommandRun == true { -+ t.Errorf("Subcommand executed when NOT expected") -+ } -+ -+} -+ -+func TestAppHelpPrinter(t *testing.T) { -+ oldPrinter := cli.HelpPrinter -+ defer func() { -+ cli.HelpPrinter = oldPrinter -+ }() -+ -+ var wasCalled = false -+ cli.HelpPrinter = func(template string, data interface{}) { -+ wasCalled = true -+ } -+ -+ app := cli.NewApp() -+ app.Run([]string{"-h"}) -+ -+ if wasCalled == false { -+ t.Errorf("Help printer expected to be called, but was not") -+ } -+} -+ -+func TestAppCommandNotFound(t *testing.T) { -+ beforeRun, subcommandRun := false, false -+ app := cli.NewApp() -+ -+ app.CommandNotFound = func(c *cli.Context, command string) { -+ beforeRun = true -+ } -+ -+ app.Commands = []cli.Command{ -+ cli.Command{ -+ Name: "bar", -+ Action: func(c *cli.Context) { -+ subcommandRun = true -+ }, -+ }, -+ } -+ -+ app.Run([]string{"command", "foo"}) -+ -+ expect(t, beforeRun, true) -+ expect(t, subcommandRun, false) -+} -+ -+func TestGlobalFlagsInSubcommands(t *testing.T) { -+ subcommandRun := false -+ app := cli.NewApp() -+ -+ app.Flags = []cli.Flag{ -+ cli.BoolFlag{Name: "debug, d", Usage: "Enable debugging"}, -+ } -+ -+ app.Commands = []cli.Command{ -+ cli.Command{ -+ Name: "foo", -+ Subcommands: []cli.Command{ -+ { -+ Name: "bar", -+ Action: func(c *cli.Context) { -+ if c.GlobalBool("debug") { -+ subcommandRun = true -+ } -+ }, -+ }, -+ }, -+ }, -+ } -+ -+ app.Run([]string{"command", "-d", "foo", "bar"}) -+ -+ expect(t, subcommandRun, true) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete docker-1/vendor/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/autocomplete/bash_autocomplete 2015-01-16 03:56:49.103152140 -0500 -@@ -0,0 +1,13 @@ -+#! /bin/bash -+ -+_cli_bash_autocomplete() { -+ local cur prev opts base -+ COMPREPLY=() -+ cur="${COMP_WORDS[COMP_CWORD]}" -+ prev="${COMP_WORDS[COMP_CWORD-1]}" -+ opts=$( ${COMP_WORDS[@]:0:COMP_CWORD} --generate-bash-completion ) -+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) -+ return 0 -+ } -+ -+ complete -F _cli_bash_autocomplete $PROG -\ No newline at end of file -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/cli.go docker-1/vendor/src/github.com/codegangsta/cli/cli.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/cli.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/cli.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,19 @@ -+// Package cli provides a minimal framework for creating and organizing command line -+// Go applications. cli is designed to be easy to understand and write, the most simple -+// cli application can be written as follows: -+// func main() { -+// cli.NewApp().Run(os.Args) -+// } -+// -+// Of course this application does not do much, so let's make this an actual application: -+// func main() { -+// app := cli.NewApp() -+// app.Name = "greet" -+// app.Usage = "say a greeting" -+// app.Action = func(c *cli.Context) { -+// println("Greetings") -+// } -+// -+// app.Run(os.Args) -+// } -+package cli -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/cli_test.go docker-1/vendor/src/github.com/codegangsta/cli/cli_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/cli_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/cli_test.go 2015-01-16 03:56:49.105152140 -0500 -@@ -0,0 +1,88 @@ -+package cli_test -+ -+import ( -+ "os" -+ -+ "github.com/codegangsta/cli" -+) -+ -+func Example() { -+ app := cli.NewApp() -+ app.Name = "todo" -+ app.Usage = "task list on the command line" -+ app.Commands = []cli.Command{ -+ { -+ Name: "add", -+ ShortName: "a", -+ Usage: "add a task to the list", -+ Action: func(c *cli.Context) { -+ println("added task: ", c.Args().First()) -+ }, -+ }, -+ { -+ Name: "complete", -+ ShortName: "c", -+ Usage: "complete a task on the list", -+ Action: func(c *cli.Context) { -+ println("completed task: ", c.Args().First()) -+ }, -+ }, -+ } -+ -+ app.Run(os.Args) -+} -+ -+func ExampleSubcommand() { -+ app := cli.NewApp() -+ app.Name = "say" -+ app.Commands = []cli.Command{ -+ { -+ Name: "hello", -+ ShortName: "hi", -+ Usage: "use it to see a description", -+ Description: "This is how we describe hello the function", -+ Subcommands: []cli.Command{ -+ { -+ Name: "english", -+ ShortName: "en", -+ Usage: "sends a greeting in english", -+ Description: "greets someone in english", -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "name", Value: "Bob", Usage: "Name of the person to greet"}, -+ }, -+ Action: func(c *cli.Context) { -+ println("Hello, ", c.String("name")) -+ }, -+ }, { -+ Name: "spanish", -+ ShortName: "sp", -+ Usage: "sends a greeting in spanish", -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "surname", Value: "Jones", Usage: "Surname of the person to greet"}, -+ }, -+ Action: func(c *cli.Context) { -+ println("Hola, ", c.String("surname")) -+ }, -+ }, { -+ Name: "french", -+ ShortName: "fr", -+ Usage: "sends a greeting in french", -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "nickname", Value: "Stevie", Usage: "Nickname of the person to greet"}, -+ }, -+ Action: func(c *cli.Context) { -+ println("Bonjour, ", c.String("nickname")) -+ }, -+ }, -+ }, -+ }, { -+ Name: "bye", -+ Usage: "says goodbye", -+ Action: func(c *cli.Context) { -+ println("bye") -+ }, -+ }, -+ } -+ -+ app.Run(os.Args) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/command.go docker-1/vendor/src/github.com/codegangsta/cli/command.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/command.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/command.go 2015-01-16 03:56:49.105152140 -0500 -@@ -0,0 +1,141 @@ -+package cli -+ -+import ( -+ "fmt" -+ "io/ioutil" -+ "strings" -+) -+ -+// Command is a subcommand for a cli.App. -+type Command struct { -+ // The name of the command -+ Name string -+ // short name of the command. Typically one character -+ ShortName string -+ // A short description of the usage of this command -+ Usage string -+ // A longer explanation of how the command works -+ Description string -+ // The function to call when checking for bash command completions -+ BashComplete func(context *Context) -+ // An action to execute before any sub-subcommands are run, but after the context is ready -+ // If a non-nil error is returned, no sub-subcommands are run -+ Before func(context *Context) error -+ // The function to call when this command is invoked -+ Action func(context *Context) -+ // List of child commands -+ Subcommands []Command -+ // List of flags to parse -+ Flags []Flag -+ // Treat all flags as normal arguments if true -+ SkipFlagParsing bool -+ // Boolean to hide built-in help command -+ HideHelp bool -+} -+ -+// Invokes the command given the context, parses ctx.Args() to generate command-specific flags -+func (c Command) Run(ctx *Context) error { -+ -+ if len(c.Subcommands) > 0 || c.Before != nil { -+ return c.startApp(ctx) -+ } -+ -+ if !c.HideHelp { -+ // append help to flags -+ c.Flags = append( -+ c.Flags, -+ HelpFlag, -+ ) -+ } -+ -+ if ctx.App.EnableBashCompletion { -+ c.Flags = append(c.Flags, BashCompletionFlag) -+ } -+ -+ set := flagSet(c.Name, c.Flags) -+ set.SetOutput(ioutil.Discard) -+ -+ firstFlagIndex := -1 -+ for index, arg := range ctx.Args() { -+ if strings.HasPrefix(arg, "-") { -+ firstFlagIndex = index -+ break -+ } -+ } -+ -+ var err error -+ if firstFlagIndex > -1 && !c.SkipFlagParsing { -+ args := ctx.Args() -+ regularArgs := args[1:firstFlagIndex] -+ flagArgs := args[firstFlagIndex:] -+ err = set.Parse(append(flagArgs, regularArgs...)) -+ } else { -+ err = set.Parse(ctx.Args().Tail()) -+ } -+ -+ if err != nil { -+ fmt.Printf("Incorrect Usage.\n\n") -+ ShowCommandHelp(ctx, c.Name) -+ fmt.Println("") -+ return err -+ } -+ -+ nerr := normalizeFlags(c.Flags, set) -+ if nerr != nil { -+ fmt.Println(nerr) -+ fmt.Println("") -+ ShowCommandHelp(ctx, c.Name) -+ fmt.Println("") -+ return nerr -+ } -+ context := NewContext(ctx.App, set, ctx.globalSet) -+ -+ if checkCommandCompletions(context, c.Name) { -+ return nil -+ } -+ -+ if checkCommandHelp(context, c.Name) { -+ return nil -+ } -+ context.Command = c -+ c.Action(context) -+ return nil -+} -+ -+// Returns true if Command.Name or Command.ShortName matches given name -+func (c Command) HasName(name string) bool { -+ return c.Name == name || c.ShortName == name -+} -+ -+func (c Command) startApp(ctx *Context) error { -+ app := NewApp() -+ -+ // set the name and usage -+ app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) -+ if c.Description != "" { -+ app.Usage = c.Description -+ } else { -+ app.Usage = c.Usage -+ } -+ -+ // set the flags and commands -+ app.Commands = c.Subcommands -+ app.Flags = c.Flags -+ app.HideHelp = c.HideHelp -+ -+ // bash completion -+ app.EnableBashCompletion = ctx.App.EnableBashCompletion -+ if c.BashComplete != nil { -+ app.BashComplete = c.BashComplete -+ } -+ -+ // set the actions -+ app.Before = c.Before -+ if c.Action != nil { -+ app.Action = c.Action -+ } else { -+ app.Action = helpSubcommand.Action -+ } -+ -+ return app.RunAsSubcommand(ctx) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/command_test.go docker-1/vendor/src/github.com/codegangsta/cli/command_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/command_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/command_test.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,48 @@ -+package cli_test -+ -+import ( -+ "flag" -+ "github.com/codegangsta/cli" -+ "testing" -+) -+ -+func TestCommandDoNotIgnoreFlags(t *testing.T) { -+ app := cli.NewApp() -+ set := flag.NewFlagSet("test", 0) -+ test := []string{"blah", "blah", "-break"} -+ set.Parse(test) -+ -+ c := cli.NewContext(app, set, set) -+ -+ command := cli.Command { -+ Name: "test-cmd", -+ ShortName: "tc", -+ Usage: "this is for testing", -+ Description: "testing", -+ Action: func(_ *cli.Context) { }, -+ } -+ err := command.Run(c) -+ -+ expect(t, err.Error(), "flag provided but not defined: -break") -+} -+ -+func TestCommandIgnoreFlags(t *testing.T) { -+ app := cli.NewApp() -+ set := flag.NewFlagSet("test", 0) -+ test := []string{"blah", "blah"} -+ set.Parse(test) -+ -+ c := cli.NewContext(app, set, set) -+ -+ command := cli.Command { -+ Name: "test-cmd", -+ ShortName: "tc", -+ Usage: "this is for testing", -+ Description: "testing", -+ Action: func(_ *cli.Context) { }, -+ SkipFlagParsing: true, -+ } -+ err := command.Run(c) -+ -+ expect(t, err, nil) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/context.go docker-1/vendor/src/github.com/codegangsta/cli/context.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/context.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/context.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,280 @@ -+package cli -+ -+import ( -+ "errors" -+ "flag" -+ "strconv" -+ "strings" -+) -+ -+// Context is a type that is passed through to -+// each Handler action in a cli application. Context -+// can be used to retrieve context-specific Args and -+// parsed command-line options. -+type Context struct { -+ App *App -+ Command Command -+ flagSet *flag.FlagSet -+ globalSet *flag.FlagSet -+ setFlags map[string]bool -+} -+ -+// Creates a new context. For use in when invoking an App or Command action. -+func NewContext(app *App, set *flag.FlagSet, globalSet *flag.FlagSet) *Context { -+ return &Context{App: app, flagSet: set, globalSet: globalSet} -+} -+ -+// Looks up the value of a local int flag, returns 0 if no int flag exists -+func (c *Context) Int(name string) int { -+ return lookupInt(name, c.flagSet) -+} -+ -+// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists -+func (c *Context) Float64(name string) float64 { -+ return lookupFloat64(name, c.flagSet) -+} -+ -+// Looks up the value of a local bool flag, returns false if no bool flag exists -+func (c *Context) Bool(name string) bool { -+ return lookupBool(name, c.flagSet) -+} -+ -+// Looks up the value of a local boolT flag, returns false if no bool flag exists -+func (c *Context) BoolT(name string) bool { -+ return lookupBoolT(name, c.flagSet) -+} -+ -+// Looks up the value of a local string flag, returns "" if no string flag exists -+func (c *Context) String(name string) string { -+ return lookupString(name, c.flagSet) -+} -+ -+// Looks up the value of a local string slice flag, returns nil if no string slice flag exists -+func (c *Context) StringSlice(name string) []string { -+ return lookupStringSlice(name, c.flagSet) -+} -+ -+// Looks up the value of a local int slice flag, returns nil if no int slice flag exists -+func (c *Context) IntSlice(name string) []int { -+ return lookupIntSlice(name, c.flagSet) -+} -+ -+// Looks up the value of a local generic flag, returns nil if no generic flag exists -+func (c *Context) Generic(name string) interface{} { -+ return lookupGeneric(name, c.flagSet) -+} -+ -+// Looks up the value of a global int flag, returns 0 if no int flag exists -+func (c *Context) GlobalInt(name string) int { -+ return lookupInt(name, c.globalSet) -+} -+ -+// Looks up the value of a global bool flag, returns false if no bool flag exists -+func (c *Context) GlobalBool(name string) bool { -+ return lookupBool(name, c.globalSet) -+} -+ -+// Looks up the value of a global string flag, returns "" if no string flag exists -+func (c *Context) GlobalString(name string) string { -+ return lookupString(name, c.globalSet) -+} -+ -+// Looks up the value of a global string slice flag, returns nil if no string slice flag exists -+func (c *Context) GlobalStringSlice(name string) []string { -+ return lookupStringSlice(name, c.globalSet) -+} -+ -+// Looks up the value of a global int slice flag, returns nil if no int slice flag exists -+func (c *Context) GlobalIntSlice(name string) []int { -+ return lookupIntSlice(name, c.globalSet) -+} -+ -+// Looks up the value of a global generic flag, returns nil if no generic flag exists -+func (c *Context) GlobalGeneric(name string) interface{} { -+ return lookupGeneric(name, c.globalSet) -+} -+ -+// Determines if the flag was actually set exists -+func (c *Context) IsSet(name string) bool { -+ if c.setFlags == nil { -+ c.setFlags = make(map[string]bool) -+ c.flagSet.Visit(func(f *flag.Flag) { -+ c.setFlags[f.Name] = true -+ }) -+ } -+ return c.setFlags[name] == true -+} -+ -+type Args []string -+ -+// Returns the command line arguments associated with the context. -+func (c *Context) Args() Args { -+ args := Args(c.flagSet.Args()) -+ return args -+} -+ -+// Returns the nth argument, or else a blank string -+func (a Args) Get(n int) string { -+ if len(a) > n { -+ return a[n] -+ } -+ return "" -+} -+ -+// Returns the first argument, or else a blank string -+func (a Args) First() string { -+ return a.Get(0) -+} -+ -+// Return the rest of the arguments (not the first one) -+// or else an empty string slice -+func (a Args) Tail() []string { -+ if len(a) >= 2 { -+ return []string(a)[1:] -+ } -+ return []string{} -+} -+ -+// Checks if there are any arguments present -+func (a Args) Present() bool { -+ return len(a) != 0 -+} -+ -+// Swaps arguments at the given indexes -+func (a Args) Swap(from, to int) error { -+ if from >= len(a) || to >= len(a) { -+ return errors.New("index out of range") -+ } -+ a[from], a[to] = a[to], a[from] -+ return nil -+} -+ -+func lookupInt(name string, set *flag.FlagSet) int { -+ f := set.Lookup(name) -+ if f != nil { -+ val, err := strconv.Atoi(f.Value.String()) -+ if err != nil { -+ return 0 -+ } -+ return val -+ } -+ -+ return 0 -+} -+ -+func lookupFloat64(name string, set *flag.FlagSet) float64 { -+ f := set.Lookup(name) -+ if f != nil { -+ val, err := strconv.ParseFloat(f.Value.String(), 64) -+ if err != nil { -+ return 0 -+ } -+ return val -+ } -+ -+ return 0 -+} -+ -+func lookupString(name string, set *flag.FlagSet) string { -+ f := set.Lookup(name) -+ if f != nil { -+ return f.Value.String() -+ } -+ -+ return "" -+} -+ -+func lookupStringSlice(name string, set *flag.FlagSet) []string { -+ f := set.Lookup(name) -+ if f != nil { -+ return (f.Value.(*StringSlice)).Value() -+ -+ } -+ -+ return nil -+} -+ -+func lookupIntSlice(name string, set *flag.FlagSet) []int { -+ f := set.Lookup(name) -+ if f != nil { -+ return (f.Value.(*IntSlice)).Value() -+ -+ } -+ -+ return nil -+} -+ -+func lookupGeneric(name string, set *flag.FlagSet) interface{} { -+ f := set.Lookup(name) -+ if f != nil { -+ return f.Value -+ } -+ return nil -+} -+ -+func lookupBool(name string, set *flag.FlagSet) bool { -+ f := set.Lookup(name) -+ if f != nil { -+ val, err := strconv.ParseBool(f.Value.String()) -+ if err != nil { -+ return false -+ } -+ return val -+ } -+ -+ return false -+} -+ -+func lookupBoolT(name string, set *flag.FlagSet) bool { -+ f := set.Lookup(name) -+ if f != nil { -+ val, err := strconv.ParseBool(f.Value.String()) -+ if err != nil { -+ return true -+ } -+ return val -+ } -+ -+ return false -+} -+ -+func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { -+ switch ff.Value.(type) { -+ case *StringSlice: -+ default: -+ set.Set(name, ff.Value.String()) -+ } -+} -+ -+func normalizeFlags(flags []Flag, set *flag.FlagSet) error { -+ visited := make(map[string]bool) -+ set.Visit(func(f *flag.Flag) { -+ visited[f.Name] = true -+ }) -+ for _, f := range flags { -+ parts := strings.Split(f.getName(), ",") -+ if len(parts) == 1 { -+ continue -+ } -+ var ff *flag.Flag -+ for _, name := range parts { -+ name = strings.Trim(name, " ") -+ if visited[name] { -+ if ff != nil { -+ return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) -+ } -+ ff = set.Lookup(name) -+ } -+ } -+ if ff == nil { -+ continue -+ } -+ for _, name := range parts { -+ name = strings.Trim(name, " ") -+ if !visited[name] { -+ copyFlag(name, ff, set) -+ } -+ } -+ } -+ return nil -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/context_test.go docker-1/vendor/src/github.com/codegangsta/cli/context_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/context_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/context_test.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,68 @@ -+package cli_test -+ -+import ( -+ "flag" -+ "github.com/codegangsta/cli" -+ "testing" -+) -+ -+func TestNewContext(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Int("myflag", 12, "doc") -+ globalSet := flag.NewFlagSet("test", 0) -+ globalSet.Int("myflag", 42, "doc") -+ command := cli.Command{Name: "mycommand"} -+ c := cli.NewContext(nil, set, globalSet) -+ c.Command = command -+ expect(t, c.Int("myflag"), 12) -+ expect(t, c.GlobalInt("myflag"), 42) -+ expect(t, c.Command.Name, "mycommand") -+} -+ -+func TestContext_Int(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Int("myflag", 12, "doc") -+ c := cli.NewContext(nil, set, set) -+ expect(t, c.Int("myflag"), 12) -+} -+ -+func TestContext_String(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.String("myflag", "hello world", "doc") -+ c := cli.NewContext(nil, set, set) -+ expect(t, c.String("myflag"), "hello world") -+} -+ -+func TestContext_Bool(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Bool("myflag", false, "doc") -+ c := cli.NewContext(nil, set, set) -+ expect(t, c.Bool("myflag"), false) -+} -+ -+func TestContext_BoolT(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Bool("myflag", true, "doc") -+ c := cli.NewContext(nil, set, set) -+ expect(t, c.BoolT("myflag"), true) -+} -+ -+func TestContext_Args(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Bool("myflag", false, "doc") -+ c := cli.NewContext(nil, set, set) -+ set.Parse([]string{"--myflag", "bat", "baz"}) -+ expect(t, len(c.Args()), 2) -+ expect(t, c.Bool("myflag"), true) -+} -+ -+func TestContext_IsSet(t *testing.T) { -+ set := flag.NewFlagSet("test", 0) -+ set.Bool("myflag", false, "doc") -+ set.String("otherflag", "hello world", "doc") -+ c := cli.NewContext(nil, set, set) -+ set.Parse([]string{"--myflag", "bat", "baz"}) -+ expect(t, c.IsSet("myflag"), true) -+ expect(t, c.IsSet("otherflag"), false) -+ expect(t, c.IsSet("bogusflag"), false) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/flag.go docker-1/vendor/src/github.com/codegangsta/cli/flag.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/flag.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/flag.go 2015-01-16 03:56:49.103152140 -0500 -@@ -0,0 +1,280 @@ -+package cli -+ -+import ( -+ "flag" -+ "fmt" -+ "strconv" -+ "strings" -+) -+ -+// This flag enables bash-completion for all commands and subcommands -+var BashCompletionFlag = BoolFlag{"generate-bash-completion", ""} -+ -+// This flag prints the version for the application -+var VersionFlag = BoolFlag{"version, v", "print the version"} -+ -+// This flag prints the help for all commands and subcommands -+var HelpFlag = BoolFlag{"help, h", "show help"} -+ -+// Flag is a common interface related to parsing flags in cli. -+// For more advanced flag parsing techniques, it is recomended that -+// this interface be implemented. -+type Flag interface { -+ fmt.Stringer -+ // Apply Flag settings to the given flag set -+ Apply(*flag.FlagSet) -+ getName() string -+} -+ -+func flagSet(name string, flags []Flag) *flag.FlagSet { -+ set := flag.NewFlagSet(name, flag.ContinueOnError) -+ -+ for _, f := range flags { -+ f.Apply(set) -+ } -+ return set -+} -+ -+func eachName(longName string, fn func(string)) { -+ parts := strings.Split(longName, ",") -+ for _, name := range parts { -+ name = strings.Trim(name, " ") -+ fn(name) -+ } -+} -+ -+// Generic is a generic parseable type identified by a specific flag -+type Generic interface { -+ Set(value string) error -+ String() string -+} -+ -+// GenericFlag is the flag type for types implementing Generic -+type GenericFlag struct { -+ Name string -+ Value Generic -+ Usage string -+} -+ -+func (f GenericFlag) String() string { -+ return fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage) -+} -+ -+func (f GenericFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Var(f.Value, name, f.Usage) -+ }) -+} -+ -+func (f GenericFlag) getName() string { -+ return f.Name -+} -+ -+type StringSlice []string -+ -+func (f *StringSlice) Set(value string) error { -+ *f = append(*f, value) -+ return nil -+} -+ -+func (f *StringSlice) String() string { -+ return fmt.Sprintf("%s", *f) -+} -+ -+func (f *StringSlice) Value() []string { -+ return *f -+} -+ -+type StringSliceFlag struct { -+ Name string -+ Value *StringSlice -+ Usage string -+} -+ -+func (f StringSliceFlag) String() string { -+ firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") -+ pref := prefixFor(firstName) -+ return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage) -+} -+ -+func (f StringSliceFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Var(f.Value, name, f.Usage) -+ }) -+} -+ -+func (f StringSliceFlag) getName() string { -+ return f.Name -+} -+ -+type IntSlice []int -+ -+func (f *IntSlice) Set(value string) error { -+ -+ tmp, err := strconv.Atoi(value) -+ if err != nil { -+ return err -+ } else { -+ *f = append(*f, tmp) -+ } -+ return nil -+} -+ -+func (f *IntSlice) String() string { -+ return fmt.Sprintf("%d", *f) -+} -+ -+func (f *IntSlice) Value() []int { -+ return *f -+} -+ -+type IntSliceFlag struct { -+ Name string -+ Value *IntSlice -+ Usage string -+} -+ -+func (f IntSliceFlag) String() string { -+ firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") -+ pref := prefixFor(firstName) -+ return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage) -+} -+ -+func (f IntSliceFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Var(f.Value, name, f.Usage) -+ }) -+} -+ -+func (f IntSliceFlag) getName() string { -+ return f.Name -+} -+ -+type BoolFlag struct { -+ Name string -+ Usage string -+} -+ -+func (f BoolFlag) String() string { -+ return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage) -+} -+ -+func (f BoolFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Bool(name, false, f.Usage) -+ }) -+} -+ -+func (f BoolFlag) getName() string { -+ return f.Name -+} -+ -+type BoolTFlag struct { -+ Name string -+ Usage string -+} -+ -+func (f BoolTFlag) String() string { -+ return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage) -+} -+ -+func (f BoolTFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Bool(name, true, f.Usage) -+ }) -+} -+ -+func (f BoolTFlag) getName() string { -+ return f.Name -+} -+ -+type StringFlag struct { -+ Name string -+ Value string -+ Usage string -+} -+ -+func (f StringFlag) String() string { -+ var fmtString string -+ fmtString = "%s %v\t%v" -+ -+ if len(f.Value) > 0 { -+ fmtString = "%s '%v'\t%v" -+ } else { -+ fmtString = "%s %v\t%v" -+ } -+ -+ return fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage) -+} -+ -+func (f StringFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.String(name, f.Value, f.Usage) -+ }) -+} -+ -+func (f StringFlag) getName() string { -+ return f.Name -+} -+ -+type IntFlag struct { -+ Name string -+ Value int -+ Usage string -+} -+ -+func (f IntFlag) String() string { -+ return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage) -+} -+ -+func (f IntFlag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Int(name, f.Value, f.Usage) -+ }) -+} -+ -+func (f IntFlag) getName() string { -+ return f.Name -+} -+ -+type Float64Flag struct { -+ Name string -+ Value float64 -+ Usage string -+} -+ -+func (f Float64Flag) String() string { -+ return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage) -+} -+ -+func (f Float64Flag) Apply(set *flag.FlagSet) { -+ eachName(f.Name, func(name string) { -+ set.Float64(name, f.Value, f.Usage) -+ }) -+} -+ -+func (f Float64Flag) getName() string { -+ return f.Name -+} -+ -+func prefixFor(name string) (prefix string) { -+ if len(name) == 1 { -+ prefix = "-" -+ } else { -+ prefix = "--" -+ } -+ -+ return -+} -+ -+func prefixedNames(fullName string) (prefixed string) { -+ parts := strings.Split(fullName, ",") -+ for i, name := range parts { -+ name = strings.Trim(name, " ") -+ prefixed += prefixFor(name) + name -+ if i < len(parts)-1 { -+ prefixed += ", " -+ } -+ } -+ return -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/flag_test.go docker-1/vendor/src/github.com/codegangsta/cli/flag_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/flag_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/flag_test.go 2015-01-16 03:56:49.103152140 -0500 -@@ -0,0 +1,194 @@ -+package cli_test -+ -+import ( -+ "github.com/codegangsta/cli" -+ -+ "fmt" -+ "reflect" -+ "strings" -+ "testing" -+) -+ -+var boolFlagTests = []struct { -+ name string -+ expected string -+}{ -+ {"help", "--help\t"}, -+ {"h", "-h\t"}, -+} -+ -+func TestBoolFlagHelpOutput(t *testing.T) { -+ -+ for _, test := range boolFlagTests { -+ flag := cli.BoolFlag{Name: test.name} -+ output := flag.String() -+ -+ if output != test.expected { -+ t.Errorf("%s does not match %s", output, test.expected) -+ } -+ } -+} -+ -+var stringFlagTests = []struct { -+ name string -+ value string -+ expected string -+}{ -+ {"help", "", "--help \t"}, -+ {"h", "", "-h \t"}, -+ {"h", "", "-h \t"}, -+ {"test", "Something", "--test 'Something'\t"}, -+} -+ -+func TestStringFlagHelpOutput(t *testing.T) { -+ -+ for _, test := range stringFlagTests { -+ flag := cli.StringFlag{Name: test.name, Value: test.value} -+ output := flag.String() -+ -+ if output != test.expected { -+ t.Errorf("%s does not match %s", output, test.expected) -+ } -+ } -+} -+ -+var intFlagTests = []struct { -+ name string -+ expected string -+}{ -+ {"help", "--help '0'\t"}, -+ {"h", "-h '0'\t"}, -+} -+ -+func TestIntFlagHelpOutput(t *testing.T) { -+ -+ for _, test := range intFlagTests { -+ flag := cli.IntFlag{Name: test.name} -+ output := flag.String() -+ -+ if output != test.expected { -+ t.Errorf("%s does not match %s", output, test.expected) -+ } -+ } -+} -+ -+var float64FlagTests = []struct { -+ name string -+ expected string -+}{ -+ {"help", "--help '0'\t"}, -+ {"h", "-h '0'\t"}, -+} -+ -+func TestFloat64FlagHelpOutput(t *testing.T) { -+ -+ for _, test := range float64FlagTests { -+ flag := cli.Float64Flag{Name: test.name} -+ output := flag.String() -+ -+ if output != test.expected { -+ t.Errorf("%s does not match %s", output, test.expected) -+ } -+ } -+} -+ -+func TestParseMultiString(t *testing.T) { -+ (&cli.App{ -+ Flags: []cli.Flag{ -+ cli.StringFlag{Name: "serve, s"}, -+ }, -+ Action: func(ctx *cli.Context) { -+ if ctx.String("serve") != "10" { -+ t.Errorf("main name not set") -+ } -+ if ctx.String("s") != "10" { -+ t.Errorf("short name not set") -+ } -+ }, -+ }).Run([]string{"run", "-s", "10"}) -+} -+ -+func TestParseMultiStringSlice(t *testing.T) { -+ (&cli.App{ -+ Flags: []cli.Flag{ -+ cli.StringSliceFlag{Name: "serve, s", Value: &cli.StringSlice{}}, -+ }, -+ Action: func(ctx *cli.Context) { -+ if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"10", "20"}) { -+ t.Errorf("main name not set") -+ } -+ if !reflect.DeepEqual(ctx.StringSlice("s"), []string{"10", "20"}) { -+ t.Errorf("short name not set") -+ } -+ }, -+ }).Run([]string{"run", "-s", "10", "-s", "20"}) -+} -+ -+func TestParseMultiInt(t *testing.T) { -+ a := cli.App{ -+ Flags: []cli.Flag{ -+ cli.IntFlag{Name: "serve, s"}, -+ }, -+ Action: func(ctx *cli.Context) { -+ if ctx.Int("serve") != 10 { -+ t.Errorf("main name not set") -+ } -+ if ctx.Int("s") != 10 { -+ t.Errorf("short name not set") -+ } -+ }, -+ } -+ a.Run([]string{"run", "-s", "10"}) -+} -+ -+func TestParseMultiBool(t *testing.T) { -+ a := cli.App{ -+ Flags: []cli.Flag{ -+ cli.BoolFlag{Name: "serve, s"}, -+ }, -+ Action: func(ctx *cli.Context) { -+ if ctx.Bool("serve") != true { -+ t.Errorf("main name not set") -+ } -+ if ctx.Bool("s") != true { -+ t.Errorf("short name not set") -+ } -+ }, -+ } -+ a.Run([]string{"run", "--serve"}) -+} -+ -+type Parser [2]string -+ -+func (p *Parser) Set(value string) error { -+ parts := strings.Split(value, ",") -+ if len(parts) != 2 { -+ return fmt.Errorf("invalid format") -+ } -+ -+ (*p)[0] = parts[0] -+ (*p)[1] = parts[1] -+ -+ return nil -+} -+ -+func (p *Parser) String() string { -+ return fmt.Sprintf("%s,%s", p[0], p[1]) -+} -+ -+func TestParseGeneric(t *testing.T) { -+ a := cli.App{ -+ Flags: []cli.Flag{ -+ cli.GenericFlag{Name: "serve, s", Value: &Parser{}}, -+ }, -+ Action: func(ctx *cli.Context) { -+ if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) { -+ t.Errorf("main name not set") -+ } -+ if !reflect.DeepEqual(ctx.Generic("s"), &Parser{"10", "20"}) { -+ t.Errorf("short name not set") -+ } -+ }, -+ } -+ a.Run([]string{"run", "-s", "10,20"}) -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/helpers_test.go docker-1/vendor/src/github.com/codegangsta/cli/helpers_test.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/helpers_test.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/helpers_test.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,19 @@ -+package cli_test -+ -+import ( -+ "reflect" -+ "testing" -+) -+ -+/* Test Helpers */ -+func expect(t *testing.T, a interface{}, b interface{}) { -+ if a != b { -+ t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) -+ } -+} -+ -+func refute(t *testing.T, a interface{}, b interface{}) { -+ if a == b { -+ t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) -+ } -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/help.go docker-1/vendor/src/github.com/codegangsta/cli/help.go ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/help.go 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/help.go 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,213 @@ -+package cli -+ -+import ( -+ "fmt" -+ "os" -+ "text/tabwriter" -+ "text/template" -+) -+ -+// The text template for the Default help topic. -+// cli.go uses text/template to render templates. You can -+// render custom help text by setting this variable. -+var AppHelpTemplate = `NAME: -+ {{.Name}} - {{.Usage}} -+ -+USAGE: -+ {{.Name}} {{ if .Flags }}[global options] {{ end }}command{{ if .Flags }} [command options]{{ end }} [arguments...] -+ -+VERSION: -+ {{.Version}} -+ -+COMMANDS: -+ {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} -+ {{end}}{{ if .Flags }} -+GLOBAL OPTIONS: -+ {{range .Flags}}{{.}} -+ {{end}}{{ end }} -+` -+ -+// The text template for the command help topic. -+// cli.go uses text/template to render templates. You can -+// render custom help text by setting this variable. -+var CommandHelpTemplate = `NAME: -+ {{.Name}} - {{.Usage}} -+ -+USAGE: -+ command {{.Name}}{{ if .Flags }} [command options]{{ end }} [arguments...] -+ -+DESCRIPTION: -+ {{.Description}}{{ if .Flags }} -+ -+OPTIONS: -+ {{range .Flags}}{{.}} -+ {{end}}{{ end }} -+` -+ -+// The text template for the subcommand help topic. -+// cli.go uses text/template to render templates. You can -+// render custom help text by setting this variable. -+var SubcommandHelpTemplate = `NAME: -+ {{.Name}} - {{.Usage}} -+ -+USAGE: -+ {{.Name}} command{{ if .Flags }} [command options]{{ end }} [arguments...] -+ -+COMMANDS: -+ {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} -+ {{end}}{{ if .Flags }} -+OPTIONS: -+ {{range .Flags}}{{.}} -+ {{end}}{{ end }} -+` -+ -+var helpCommand = Command{ -+ Name: "help", -+ ShortName: "h", -+ Usage: "Shows a list of commands or help for one command", -+ Action: func(c *Context) { -+ args := c.Args() -+ if args.Present() { -+ ShowCommandHelp(c, args.First()) -+ } else { -+ ShowAppHelp(c) -+ } -+ }, -+} -+ -+var helpSubcommand = Command{ -+ Name: "help", -+ ShortName: "h", -+ Usage: "Shows a list of commands or help for one command", -+ Action: func(c *Context) { -+ args := c.Args() -+ if args.Present() { -+ ShowCommandHelp(c, args.First()) -+ } else { -+ ShowSubcommandHelp(c) -+ } -+ }, -+} -+ -+// Prints help for the App -+var HelpPrinter = printHelp -+ -+func ShowAppHelp(c *Context) { -+ HelpPrinter(AppHelpTemplate, c.App) -+} -+ -+// Prints the list of subcommands as the default app completion method -+func DefaultAppComplete(c *Context) { -+ for _, command := range c.App.Commands { -+ fmt.Println(command.Name) -+ if command.ShortName != "" { -+ fmt.Println(command.ShortName) -+ } -+ } -+} -+ -+// Prints help for the given command -+func ShowCommandHelp(c *Context, command string) { -+ for _, c := range c.App.Commands { -+ if c.HasName(command) { -+ HelpPrinter(CommandHelpTemplate, c) -+ return -+ } -+ } -+ -+ if c.App.CommandNotFound != nil { -+ c.App.CommandNotFound(c, command) -+ } else { -+ fmt.Printf("No help topic for '%v'\n", command) -+ } -+} -+ -+// Prints help for the given subcommand -+func ShowSubcommandHelp(c *Context) { -+ HelpPrinter(SubcommandHelpTemplate, c.App) -+} -+ -+// Prints the version number of the App -+func ShowVersion(c *Context) { -+ fmt.Printf("%v version %v\n", c.App.Name, c.App.Version) -+} -+ -+// Prints the lists of commands within a given context -+func ShowCompletions(c *Context) { -+ a := c.App -+ if a != nil && a.BashComplete != nil { -+ a.BashComplete(c) -+ } -+} -+ -+// Prints the custom completions for a given command -+func ShowCommandCompletions(ctx *Context, command string) { -+ c := ctx.App.Command(command) -+ if c != nil && c.BashComplete != nil { -+ c.BashComplete(ctx) -+ } -+} -+ -+func printHelp(templ string, data interface{}) { -+ w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) -+ t := template.Must(template.New("help").Parse(templ)) -+ err := t.Execute(w, data) -+ if err != nil { -+ panic(err) -+ } -+ w.Flush() -+} -+ -+func checkVersion(c *Context) bool { -+ if c.GlobalBool("version") { -+ ShowVersion(c) -+ return true -+ } -+ -+ return false -+} -+ -+func checkHelp(c *Context) bool { -+ if c.GlobalBool("h") || c.GlobalBool("help") { -+ ShowAppHelp(c) -+ return true -+ } -+ -+ return false -+} -+ -+func checkCommandHelp(c *Context, name string) bool { -+ if c.Bool("h") || c.Bool("help") { -+ ShowCommandHelp(c, name) -+ return true -+ } -+ -+ return false -+} -+ -+func checkSubcommandHelp(c *Context) bool { -+ if c.GlobalBool("h") || c.GlobalBool("help") { -+ ShowSubcommandHelp(c) -+ return true -+ } -+ -+ return false -+} -+ -+func checkCompletions(c *Context) bool { -+ if c.GlobalBool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { -+ ShowCompletions(c) -+ return true -+ } -+ -+ return false -+} -+ -+func checkCommandCompletions(c *Context, name string) bool { -+ if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { -+ ShowCommandCompletions(c, name) -+ return true -+ } -+ -+ return false -+} -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/LICENSE docker-1/vendor/src/github.com/codegangsta/cli/LICENSE ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/LICENSE 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/LICENSE 2015-01-16 03:56:49.105152140 -0500 -@@ -0,0 +1,21 @@ -+Copyright (C) 2013 Jeremy Saenz -+All Rights Reserved. -+ -+MIT LICENSE -+ -+Permission is hereby granted, free of charge, to any person obtaining a copy of -+this software and associated documentation files (the "Software"), to deal in -+the Software without restriction, including without limitation the rights to -+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -+the Software, and to permit persons to whom the Software is furnished to do so, -+subject to the following conditions: -+ -+The above copyright notice and this permission notice shall be included in all -+copies or substantial portions of the Software. -+ -+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/README.md docker-1/vendor/src/github.com/codegangsta/cli/README.md ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/README.md 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/README.md 2015-01-16 03:56:49.105152140 -0500 -@@ -0,0 +1,257 @@ -+[](https://travis-ci.org/codegangsta/cli) -+ -+# cli.go -+cli.go is simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way. -+ -+You can view the API docs here: -+http://godoc.org/github.com/codegangsta/cli -+ -+## Overview -+Command line apps are usually so tiny that there is absolutely no reason why your code should *not* be self-documenting. Things like generating help text and parsing command flags/options should not hinder productivity when writing a command line app. -+ -+This is where cli.go comes into play. cli.go makes command line programming fun, organized, and expressive! -+ -+## Installation -+Make sure you have a working Go environment (go 1.1 is *required*). [See the install instructions](http://golang.org/doc/install.html). -+ -+To install cli.go, simply run: -+``` -+$ go get github.com/codegangsta/cli -+``` -+ -+Make sure your PATH includes to the `$GOPATH/bin` directory so your commands can be easily used: -+``` -+export PATH=$PATH:$GOPATH/bin -+``` -+ -+## Getting Started -+One of the philosophies behind cli.go is that an API should be playful and full of discovery. So a cli.go app can be as little as one line of code in `main()`. -+ -+``` go -+package main -+ -+import ( -+ "os" -+ "github.com/codegangsta/cli" -+) -+ -+func main() { -+ cli.NewApp().Run(os.Args) -+} -+``` -+ -+This app will run and show help text, but is not very useful. Let's give an action to execute and some help documentation: -+ -+``` go -+package main -+ -+import ( -+ "os" -+ "github.com/codegangsta/cli" -+) -+ -+func main() { -+ app := cli.NewApp() -+ app.Name = "boom" -+ app.Usage = "make an explosive entrance" -+ app.Action = func(c *cli.Context) { -+ println("boom! I say!") -+ } -+ -+ app.Run(os.Args) -+} -+``` -+ -+Running this already gives you a ton of functionality, plus support for things like subcommands and flags, which are covered below. -+ -+## Example -+ -+Being a programmer can be a lonely job. Thankfully by the power of automation that is not the case! Let's create a greeter app to fend off our demons of loneliness! -+ -+``` go -+/* greet.go */ -+package main -+ -+import ( -+ "os" -+ "github.com/codegangsta/cli" -+) -+ -+func main() { -+ app := cli.NewApp() -+ app.Name = "greet" -+ app.Usage = "fight the loneliness!" -+ app.Action = func(c *cli.Context) { -+ println("Hello friend!") -+ } -+ -+ app.Run(os.Args) -+} -+``` -+ -+Install our command to the `$GOPATH/bin` directory: -+ -+``` -+$ go install -+``` -+ -+Finally run our new command: -+ -+``` -+$ greet -+Hello friend! -+``` -+ -+cli.go also generates some bitchass help text: -+``` -+$ greet help -+NAME: -+ greet - fight the loneliness! -+ -+USAGE: -+ greet [global options] command [command options] [arguments...] -+ -+VERSION: -+ 0.0.0 -+ -+COMMANDS: -+ help, h Shows a list of commands or help for one command -+ -+GLOBAL OPTIONS -+ --version Shows version information -+``` -+ -+### Arguments -+You can lookup arguments by calling the `Args` function on cli.Context. -+ -+``` go -+... -+app.Action = func(c *cli.Context) { -+ println("Hello", c.Args()[0]) -+} -+... -+``` -+ -+### Flags -+Setting and querying flags is simple. -+``` go -+... -+app.Flags = []cli.Flag { -+ cli.StringFlag{Name: "lang", Value: "english", Usage: "language for the greeting"}, -+} -+app.Action = func(c *cli.Context) { -+ name := "someone" -+ if len(c.Args()) > 0 { -+ name = c.Args()[0] -+ } -+ if c.String("lang") == "spanish" { -+ println("Hola", name) -+ } else { -+ println("Hello", name) -+ } -+} -+... -+``` -+ -+#### Alternate Names -+ -+You can set alternate (or short) names for flags by providing a comma-delimited list for the Name. e.g. -+ -+``` go -+app.Flags = []cli.Flag { -+ cli.StringFlag{Name: "lang, l", Value: "english", Usage: "language for the greeting"}, -+} -+``` -+ -+That flag can then be set with `--lang spanish` or `-l spanish`. Note that giving two different forms of the same flag in the same command invocation is an error. -+ -+### Subcommands -+ -+Subcommands can be defined for a more git-like command line app. -+```go -+... -+app.Commands = []cli.Command{ -+ { -+ Name: "add", -+ ShortName: "a", -+ Usage: "add a task to the list", -+ Action: func(c *cli.Context) { -+ println("added task: ", c.Args().First()) -+ }, -+ }, -+ { -+ Name: "complete", -+ ShortName: "c", -+ Usage: "complete a task on the list", -+ Action: func(c *cli.Context) { -+ println("completed task: ", c.Args().First()) -+ }, -+ }, -+ { -+ Name: "template", -+ ShortName: "r", -+ Usage: "options for task templates", -+ Subcommands: []cli.Command{ -+ { -+ Name: "add", -+ Usage: "add a new template", -+ Action: func(c *cli.Context) { -+ println("new task template: ", c.Args().First()) -+ }, -+ }, -+ { -+ Name: "remove", -+ Usage: "remove an existing template", -+ Action: func(c *cli.Context) { -+ println("removed task template: ", c.Args().First()) -+ }, -+ }, -+ }, -+ }, -+} -+... -+``` -+ -+### Bash Completion -+ -+You can enable completion commands by setting the EnableBashCompletion -+flag on the App object. By default, this setting will only auto-complete to -+show an app's subcommands, but you can write your own completion methods for -+the App or its subcommands. -+```go -+... -+var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"} -+app := cli.NewApp() -+app.EnableBashCompletion = true -+app.Commands = []cli.Command{ -+ { -+ Name: "complete", -+ ShortName: "c", -+ Usage: "complete a task on the list", -+ Action: func(c *cli.Context) { -+ println("completed task: ", c.Args().First()) -+ }, -+ BashComplete: func(c *cli.Context) { -+ // This will complete if no args are passed -+ if len(c.Args()) > 0 { -+ return -+ } -+ for _, t := range tasks { -+ println(t) -+ } -+ }, -+ } -+} -+... -+``` -+ -+#### To Enable -+ -+Source the autocomplete/bash_autocomplete file in your .bashrc file while -+setting the PROG variable to the name of your program: -+ -+`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete` -+ -+ -+## About -+cli.go is written by none other than the [Code Gangsta](http://codegangsta.io) -diff -uNr docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/.travis.yml docker-1/vendor/src/github.com/codegangsta/cli/.travis.yml ---- docker-6ee24211b4111e0b1e1bd7a46c5a3c4ced1b2ffa/vendor/src/github.com/codegangsta/cli/.travis.yml 1969-12-31 19:00:00.000000000 -0500 -+++ docker-1/vendor/src/github.com/codegangsta/cli/.travis.yml 2015-01-16 03:56:49.104152140 -0500 -@@ -0,0 +1,6 @@ -+language: go -+go: 1.1 -+ -+script: -+- go vet ./... -+- go test -v ./... diff --git a/SOURCES/dev.patch b/SOURCES/dev.patch new file mode 100644 index 0000000..b7c19d2 --- /dev/null +++ b/SOURCES/dev.patch @@ -0,0 +1,78 @@ +From 40b0f129f5a6e005a949dc0ba808fb9ee557ebe4 Mon Sep 17 00:00:00 2001 +From: Mrunal Patel <mrunalp@gmail.com> +Date: Fri, 9 Oct 2015 17:57:44 -0400 +Subject: [PATCH] Cherry pick changes for allowing /dev mount from host + +docker #16639 + +runc commit id c9d58506297e + +Signed-off-by: Mrunal Patel <mrunalp@gmail.com> +--- + daemon/execdriver/native/create.go | 1 + + .../runc/libcontainer/rootfs_linux.go | 26 +++++++++++++--------- + 2 files changed, 17 insertions(+), 10 deletions(-) + +diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go +index bbc83fe..ca8d7fd 100644 +--- a/daemon/execdriver/native/create.go ++++ b/daemon/execdriver/native/create.go +@@ -234,6 +234,7 @@ func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) e + for _, m := range container.Mounts { + if _, ok := userMounts[m.Destination]; !ok { + if mountDev && strings.HasPrefix(m.Destination, "/dev/") { ++ container.Devices = nil + continue + } + defaultMounts = append(defaultMounts, m) +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +index a211d8d..9fd7058 100644 +--- a/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/rootfs_linux.go +@@ -27,6 +27,8 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + if err := prepareRoot(config); err != nil { + return newSystemError(err) + } ++ ++ setupDev := len(config.Devices) == 0 + for _, m := range config.Mounts { + for _, precmd := range m.PremountCmds { + if err := mountCmd(precmd); err != nil { +@@ -43,14 +45,16 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + } + } + } +- if err := createDevices(config); err != nil { +- return newSystemError(err) +- } +- if err := setupPtmx(config, console); err != nil { +- return newSystemError(err) +- } +- if err := setupDevSymlinks(config.Rootfs); err != nil { +- return newSystemError(err) ++ if !setupDev { ++ if err := createDevices(config); err != nil { ++ return newSystemError(err) ++ } ++ if err := setupPtmx(config, console); err != nil { ++ return newSystemError(err) ++ } ++ if err := setupDevSymlinks(config.Rootfs); err != nil { ++ return newSystemError(err) ++ } + } + if err := syscall.Chdir(config.Rootfs); err != nil { + return newSystemError(err) +@@ -63,8 +67,10 @@ func setupRootfs(config *configs.Config, console *linuxConsole) (err error) { + if err != nil { + return newSystemError(err) + } +- if err := reOpenDevNull(config.Rootfs); err != nil { +- return newSystemError(err) ++ if !setupDev { ++ if err := reOpenDevNull(config.Rootfs); err != nil { ++ return newSystemError(err) ++ } + } + if config.Readonlyfs { + if err := setReadonly(); err != nil { diff --git a/SOURCES/docker-logrotate.sh b/SOURCES/docker-logrotate.sh index 27fb979..f6fc50c 100644 --- a/SOURCES/docker-logrotate.sh +++ b/SOURCES/docker-logrotate.sh @@ -5,7 +5,7 @@ LOGROTATE=true if [ $LOGROTATE == true ]; then for id in $(docker ps -q); do - exec $(docker exec $id logrotate -s /var/log/logstatus /etc/logrotate.conf > /dev/null 2&>1) + exec $(docker exec $id logrotate -s /var/log/logstatus /etc/logrotate.conf > /dev/null 2>&1) done fi exit 0 diff --git a/SOURCES/docker-py-remove-lock.patch b/SOURCES/docker-py-remove-lock.patch deleted file mode 100644 index 596a056..0000000 --- a/SOURCES/docker-py-remove-lock.patch +++ /dev/null @@ -1,43 +0,0 @@ -From cb75275827e762a716a15459bb540a423f1fed3c Mon Sep 17 00:00:00 2001 -From: Lokesh Mandvekar <lsm5@fedoraproject.org> -Date: Wed, 8 Jul 2015 12:04:17 -0500 -Subject: [PATCH] remove lock - -atomic doesn't work on rhel without this :( - -Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> ---- - docker/unixconn/unixconn.py | 17 ++++++++--------- - 1 file changed, 8 insertions(+), 9 deletions(-) - -diff --git a/docker/unixconn/unixconn.py b/docker/unixconn/unixconn.py -index 551bd29..4c4c8e5 100644 ---- a/docker/unixconn/unixconn.py -+++ b/docker/unixconn/unixconn.py -@@ -68,15 +68,14 @@ class UnixAdapter(requests.adapters.HTTPAdapter): - super(UnixAdapter, self).__init__() - - def get_connection(self, url, proxies=None): -- with self.pools.lock: -- pool = self.pools.get(url) -- if pool: -- return pool -- -- pool = UnixHTTPConnectionPool(url, -- self.socket_path, -- self.timeout) -- self.pools[url] = pool -+ pool = self.pools.get(url) -+ if pool: -+ return pool -+ -+ pool = UnixHTTPConnectionPool(url, -+ self.socket_path, -+ self.timeout) -+ self.pools[url] = pool - - return pool - --- -2.4.5 - diff --git a/SOURCES/docker.service b/SOURCES/docker.service index c93bfdc..7a19251 100644 --- a/SOURCES/docker.service +++ b/SOURCES/docker.service @@ -10,7 +10,7 @@ EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network Environment=GOTRACEBACK=crash -ExecStart=/usr/bin/docker -d $OPTIONS \ +ExecStart=/usr/bin/docker daemon $OPTIONS \ $DOCKER_STORAGE_OPTIONS \ $DOCKER_NETWORK_OPTIONS \ $ADD_REGISTRY \ @@ -20,6 +20,7 @@ LimitNOFILE=1048576 LimitNPROC=1048576 LimitCORE=infinity MountFlags=slave +TimeoutStartSec=1min [Install] WantedBy=multi-user.target diff --git a/SOURCES/docker.sysconfig b/SOURCES/docker.sysconfig index 6e83766..196c66f 100644 --- a/SOURCES/docker.sysconfig +++ b/SOURCES/docker.sysconfig @@ -9,7 +9,7 @@ DOCKER_CERT_PATH=/etc/docker # pull use the ADD_REGISTRY option to list a set of registries, each prepended # with --add-registry flag. The first registry added will be the first registry # searched. -# ADD_REGISTRY='--add-registry registry.access.redhat.com' +ADD_REGISTRY='--add-registry registry.access.redhat.com' # If you want to block registries from being used, uncomment the BLOCK_REGISTRY # option and give it a set of registries, each prepended with --block-registry diff --git a/SOURCES/go-md2man.patch b/SOURCES/go-md2man.patch deleted file mode 100644 index 00c0cca..0000000 --- a/SOURCES/go-md2man.patch +++ /dev/null @@ -1,12414 +0,0 @@ -From 4e3b8e37a34c9b6678320e6fcdad686fb481a58f Mon Sep 17 00:00:00 2001 -From: Lokesh Mandvekar <lsm5@fedoraproject.org> -Date: Thu, 30 Apr 2015 10:35:34 -0400 -Subject: [PATCH] include updated go-md2man and deps - -Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> ---- - .../src/github.com/cpuguy83/go-md2man/LICENSE.md | 21 + - vendor/src/github.com/cpuguy83/go-md2man/README.md | 11 + - .../github.com/cpuguy83/go-md2man/go-md2man.1.md | 21 + - .../github.com/cpuguy83/go-md2man/mangen/mangen.go | 272 ++++ - vendor/src/github.com/cpuguy83/go-md2man/md2man.go | 55 + - .../github.com/russross/blackfriday/.travis.yml | 17 + - .../github.com/russross/blackfriday/LICENSE.txt | 29 + - .../src/github.com/russross/blackfriday/README.md | 246 ++++ - .../src/github.com/russross/blackfriday/block.go | 1339 ++++++++++++++++++++ - .../github.com/russross/blackfriday/block_test.go | 1296 +++++++++++++++++++ - vendor/src/github.com/russross/blackfriday/html.go | 922 ++++++++++++++ - .../src/github.com/russross/blackfriday/inline.go | 1096 ++++++++++++++++ - .../github.com/russross/blackfriday/inline_test.go | 958 ++++++++++++++ - .../src/github.com/russross/blackfriday/latex.go | 332 +++++ - .../github.com/russross/blackfriday/markdown.go | 838 ++++++++++++ - .../github.com/russross/blackfriday/ref_test.go | 128 ++ - .../github.com/russross/blackfriday/smartypants.go | 398 ++++++ - .../testdata/Amps and angle encoding.html | 17 + - .../testdata/Amps and angle encoding.text | 21 + - .../russross/blackfriday/testdata/Auto links.html | 18 + - .../russross/blackfriday/testdata/Auto links.text | 13 + - .../blackfriday/testdata/Backslash escapes.html | 123 ++ - .../blackfriday/testdata/Backslash escapes.text | 126 ++ - .../testdata/Blockquotes with code blocks.html | 15 + - .../testdata/Blockquotes with code blocks.text | 11 + - .../russross/blackfriday/testdata/Code Blocks.html | 18 + - .../russross/blackfriday/testdata/Code Blocks.text | 14 + - .../russross/blackfriday/testdata/Code Spans.html | 5 + - .../russross/blackfriday/testdata/Code Spans.text | 6 + - ...list-like lines no empty line before block.html | 14 + - ...list-like lines no empty line before block.text | 8 + - ...rd-wrapped paragraphs with list-like lines.html | 8 + - ...rd-wrapped paragraphs with list-like lines.text | 8 + - .../blackfriday/testdata/Horizontal rules.html | 71 ++ - .../blackfriday/testdata/Horizontal rules.text | 67 + - .../testdata/Inline HTML (Advanced).html | 15 + - .../testdata/Inline HTML (Advanced).text | 15 + - .../blackfriday/testdata/Inline HTML (Simple).html | 72 ++ - .../blackfriday/testdata/Inline HTML (Simple).text | 69 + - .../blackfriday/testdata/Inline HTML comments.html | 13 + - .../blackfriday/testdata/Inline HTML comments.text | 13 + - .../blackfriday/testdata/Links, inline style.html | 11 + - .../blackfriday/testdata/Links, inline style.text | 12 + - .../testdata/Links, reference style.html | 52 + - .../testdata/Links, reference style.text | 71 ++ - .../testdata/Links, shortcut references.html | 9 + - .../testdata/Links, shortcut references.text | 20 + - .../testdata/Literal quotes in titles.html | 3 + - .../testdata/Literal quotes in titles.text | 7 + - .../testdata/Markdown Documentation - Basics.html | 314 +++++ - .../testdata/Markdown Documentation - Basics.text | 306 +++++ - .../testdata/Markdown Documentation - Syntax.html | 946 ++++++++++++++ - .../testdata/Markdown Documentation - Syntax.text | 888 +++++++++++++ - .../blackfriday/testdata/Nested blockquotes.html | 9 + - .../blackfriday/testdata/Nested blockquotes.text | 5 + - .../testdata/Ordered and unordered lists.html | 166 +++ - .../testdata/Ordered and unordered lists.text | 131 ++ - .../testdata/Strong and em together.html | 7 + - .../testdata/Strong and em together.text | 7 + - .../russross/blackfriday/testdata/Tabs.html | 26 + - .../russross/blackfriday/testdata/Tabs.text | 21 + - .../russross/blackfriday/testdata/Tidyness.html | 9 + - .../russross/blackfriday/testdata/Tidyness.text | 5 + - .../shurcooL/sanitized_anchor_name/.travis.yml | 10 + - .../shurcooL/sanitized_anchor_name/README.md | 25 + - .../shurcooL/sanitized_anchor_name/main.go | 29 + - .../shurcooL/sanitized_anchor_name/main_test.go | 35 + - 67 files changed, 11863 insertions(+) - create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md - create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/README.md - create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md - create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go - create mode 100644 vendor/src/github.com/cpuguy83/go-md2man/md2man.go - create mode 100644 vendor/src/github.com/russross/blackfriday/.travis.yml - create mode 100644 vendor/src/github.com/russross/blackfriday/LICENSE.txt - create mode 100644 vendor/src/github.com/russross/blackfriday/README.md - create mode 100644 vendor/src/github.com/russross/blackfriday/block.go - create mode 100644 vendor/src/github.com/russross/blackfriday/block_test.go - create mode 100644 vendor/src/github.com/russross/blackfriday/html.go - create mode 100644 vendor/src/github.com/russross/blackfriday/inline.go - create mode 100644 vendor/src/github.com/russross/blackfriday/inline_test.go - create mode 100644 vendor/src/github.com/russross/blackfriday/latex.go - create mode 100644 vendor/src/github.com/russross/blackfriday/markdown.go - create mode 100644 vendor/src/github.com/russross/blackfriday/ref_test.go - create mode 100644 vendor/src/github.com/russross/blackfriday/smartypants.go - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Auto links.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Auto links.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tabs.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tabs.text - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html - create mode 100644 vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text - create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml - create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md - create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go - create mode 100644 vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go - -diff --git a/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md b/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md -new file mode 100644 -index 0000000..1cade6c ---- /dev/null -+++ b/vendor/src/github.com/cpuguy83/go-md2man/LICENSE.md -@@ -0,0 +1,21 @@ -+The MIT License (MIT) -+ -+Copyright (c) 2014 Brian Goff -+ -+Permission is hereby granted, free of charge, to any person obtaining a copy -+of this software and associated documentation files (the "Software"), to deal -+in the Software without restriction, including without limitation the rights -+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -+copies of the Software, and to permit persons to whom the Software is -+furnished to do so, subject to the following conditions: -+ -+The above copyright notice and this permission notice shall be included in all -+copies or substantial portions of the Software. -+ -+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -+SOFTWARE. -diff --git a/vendor/src/github.com/cpuguy83/go-md2man/README.md b/vendor/src/github.com/cpuguy83/go-md2man/README.md -new file mode 100644 -index 0000000..8eb4b2e ---- /dev/null -+++ b/vendor/src/github.com/cpuguy83/go-md2man/README.md -@@ -0,0 +1,11 @@ -+go-md2man -+========= -+ -+** Work in Progress ** -+This still needs a lot of help to be complete, or even usable! -+ -+Uses blackfriday to process markdown into man pages. -+ -+### Usage -+ -+./md2man -in /path/to/markdownfile.md -out /manfile/output/path -diff --git a/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md b/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md -new file mode 100644 -index 0000000..1f7096a ---- /dev/null -+++ b/vendor/src/github.com/cpuguy83/go-md2man/go-md2man.1.md -@@ -0,0 +1,21 @@ -+go-md2man 1 "January 2015" go-md2man "User Manual" -+================================================== -+ -+# NAME -+ go-md2man - Convert mardown files into manpages -+ -+# SYNOPSIS -+ go-md2man -in=[/path/to/md/file] -out=[/path/to/output] -+ -+# Description -+ go-md2man converts standard markdown formatted documents into manpages. It is -+ written purely in Go so as to reduce dependencies on 3rd party libs. -+ -+# Example -+ Convert the markdown file "go-md2man.1.md" into a manpage. -+ -+ go-md2man -in=README.md -out=go-md2man.1.out -+ -+# HISTORY -+ January 2015, Originally compiled by Brian Goff( cpuguy83@gmail.com ) -+ -diff --git a/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go b/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go -new file mode 100644 -index 0000000..d436eed ---- /dev/null -+++ b/vendor/src/github.com/cpuguy83/go-md2man/mangen/mangen.go -@@ -0,0 +1,272 @@ -+package mangen -+ -+import ( -+ "bytes" -+ "fmt" -+ "strings" -+ -+ "github.com/russross/blackfriday" -+) -+ -+type Man struct{} -+ -+func ManRenderer(flags int) blackfriday.Renderer { -+ return &Man{} -+} -+ -+func (m *Man) GetFlags() int { -+ return 0 -+} -+ -+func (m *Man) TitleBlock(out *bytes.Buffer, text []byte) { -+ out.WriteString(".TH ") -+ -+ splitText := bytes.Split(text, []byte("\n")) -+ for i, line := range splitText { -+ line = bytes.TrimPrefix(line, []byte("% ")) -+ if i == 0 { -+ line = bytes.Replace(line, []byte("("), []byte("\" \""), 1) -+ line = bytes.Replace(line, []byte(")"), []byte("\" \""), 1) -+ } -+ line = append([]byte("\""), line...) -+ line = append(line, []byte("\" ")...) -+ out.Write(line) -+ } -+ -+ out.WriteString(" \"\"\n") -+} -+ -+func (m *Man) BlockCode(out *bytes.Buffer, text []byte, lang string) { -+ out.WriteString("\n.PP\n.RS\n\n.nf\n") -+ escapeSpecialChars(out, text) -+ out.WriteString("\n.fi\n.RE\n") -+} -+ -+func (m *Man) BlockQuote(out *bytes.Buffer, text []byte) { -+ out.WriteString("\n.PP\n.RS\n") -+ out.Write(text) -+ out.WriteString("\n.RE\n") -+} -+ -+func (m *Man) BlockHtml(out *bytes.Buffer, text []byte) { -+ fmt.Errorf("man: BlockHtml not supported") -+ out.Write(text) -+} -+ -+func (m *Man) Header(out *bytes.Buffer, text func() bool, level int, id string) { -+ marker := out.Len() -+ -+ switch { -+ case marker == 0: -+ // This is the doc header -+ out.WriteString(".TH ") -+ case level == 1: -+ out.WriteString("\n\n.SH ") -+ case level == 2: -+ out.WriteString("\n.SH ") -+ default: -+ out.WriteString("\n.SS ") -+ } -+ -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+} -+ -+func (m *Man) HRule(out *bytes.Buffer) { -+ out.WriteString("\n.ti 0\n\\l'\\n(.lu'\n") -+} -+ -+func (m *Man) List(out *bytes.Buffer, text func() bool, flags int) { -+ marker := out.Len() -+ out.WriteString(".IP ") -+ if flags&blackfriday.LIST_TYPE_ORDERED != 0 { -+ out.WriteString("\\(bu 2") -+ } else { -+ out.WriteString("\\n+[step" + string(flags) + "]") -+ } -+ out.WriteString("\n") -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ -+} -+ -+func (m *Man) ListItem(out *bytes.Buffer, text []byte, flags int) { -+ out.WriteString("\n\\item ") -+ out.Write(text) -+} -+ -+func (m *Man) Paragraph(out *bytes.Buffer, text func() bool) { -+ marker := out.Len() -+ out.WriteString("\n.PP\n") -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ if marker != 0 { -+ out.WriteString("\n") -+ } -+} -+ -+// TODO: This might now work -+func (m *Man) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { -+ out.WriteString(".TS\nallbox;\n") -+ -+ out.Write(header) -+ out.Write(body) -+ out.WriteString("\n.TE\n") -+} -+ -+func (m *Man) TableRow(out *bytes.Buffer, text []byte) { -+ if out.Len() > 0 { -+ out.WriteString("\n") -+ } -+ out.Write(text) -+ out.WriteString("\n") -+} -+ -+func (m *Man) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { -+ if out.Len() > 0 { -+ out.WriteString(" ") -+ } -+ out.Write(text) -+ out.WriteString(" ") -+} -+ -+// TODO: This is probably broken -+func (m *Man) TableCell(out *bytes.Buffer, text []byte, align int) { -+ if out.Len() > 0 { -+ out.WriteString("\t") -+ } -+ out.Write(text) -+ out.WriteString("\t") -+} -+ -+func (m *Man) Footnotes(out *bytes.Buffer, text func() bool) { -+ -+} -+ -+func (m *Man) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { -+ -+} -+ -+func (m *Man) AutoLink(out *bytes.Buffer, link []byte, kind int) { -+ out.WriteString("\n\\[la]") -+ out.Write(link) -+ out.WriteString("\\[ra]") -+} -+ -+func (m *Man) CodeSpan(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\fB\\fC") -+ escapeSpecialChars(out, text) -+ out.WriteString("\\fR") -+} -+ -+func (m *Man) DoubleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\fB") -+ out.Write(text) -+ out.WriteString("\\fP") -+} -+ -+func (m *Man) Emphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\fI") -+ out.Write(text) -+ out.WriteString("\\fP") -+} -+ -+func (m *Man) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { -+ fmt.Errorf("man: Image not supported") -+} -+ -+func (m *Man) LineBreak(out *bytes.Buffer) { -+ out.WriteString("\n.br\n") -+} -+ -+func (m *Man) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { -+ m.AutoLink(out, link, 0) -+} -+ -+func (m *Man) RawHtmlTag(out *bytes.Buffer, tag []byte) { -+ out.Write(tag) -+} -+ -+func (m *Man) TripleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\s+2") -+ out.Write(text) -+ out.WriteString("\\s-2") -+} -+ -+func (m *Man) StrikeThrough(out *bytes.Buffer, text []byte) { -+ fmt.Errorf("man: strikethrough not supported") -+} -+ -+func (m *Man) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { -+ -+} -+ -+func (m *Man) Entity(out *bytes.Buffer, entity []byte) { -+ // TODO: convert this into a unicode character or something -+ out.Write(entity) -+} -+ -+func processFooterText(text []byte) []byte { -+ text = bytes.TrimPrefix(text, []byte("% ")) -+ newText := []byte{} -+ textArr := strings.Split(string(text), ") ") -+ -+ for i, w := range textArr { -+ if i == 0 { -+ w = strings.Replace(w, "(", "\" \"", 1) -+ w = fmt.Sprintf("\"%s\"", w) -+ } else { -+ w = fmt.Sprintf(" \"%s\"", w) -+ } -+ newText = append(newText, []byte(w)...) -+ } -+ newText = append(newText, []byte(" \"\"")...) -+ -+ return newText -+} -+ -+func (m *Man) NormalText(out *bytes.Buffer, text []byte) { -+ escapeSpecialChars(out, text) -+} -+ -+func (m *Man) DocumentHeader(out *bytes.Buffer) { -+} -+ -+func (m *Man) DocumentFooter(out *bytes.Buffer) { -+} -+ -+func needsBackslash(c byte) bool { -+ for _, r := range []byte("-_{}&\\~") { -+ if c == r { -+ return true -+ } -+ } -+ return false -+} -+ -+func escapeSpecialChars(out *bytes.Buffer, text []byte) { -+ for i := 0; i < len(text); i++ { -+ // directly copy normal characters -+ org := i -+ -+ for i < len(text) && !needsBackslash(text[i]) { -+ i++ -+ } -+ if i > org { -+ out.Write(text[org:i]) -+ } -+ -+ // escape a character -+ if i >= len(text) { -+ break -+ } -+ out.WriteByte('\\') -+ out.WriteByte(text[i]) -+ } -+} -diff --git a/vendor/src/github.com/cpuguy83/go-md2man/md2man.go b/vendor/src/github.com/cpuguy83/go-md2man/md2man.go -new file mode 100644 -index 0000000..f8b1722 ---- /dev/null -+++ b/vendor/src/github.com/cpuguy83/go-md2man/md2man.go -@@ -0,0 +1,55 @@ -+package main -+ -+import ( -+ "flag" -+ "fmt" -+ "io/ioutil" -+ "os" -+ -+ "github.com/cpuguy83/go-md2man/mangen" -+ "github.com/russross/blackfriday" -+) -+ -+var inFilePath = flag.String("in", "", "Path to file to be processed") -+var outFilePath = flag.String("out", "", "Path to output processed file") -+ -+func main() { -+ flag.Parse() -+ -+ inFile, err := os.Open(*inFilePath) -+ if err != nil { -+ fmt.Println(err) -+ os.Exit(1) -+ } -+ defer inFile.Close() -+ -+ doc, err := ioutil.ReadAll(inFile) -+ if err != nil { -+ fmt.Println(err) -+ os.Exit(1) -+ } -+ -+ renderer := mangen.ManRenderer(0) -+ extensions := 0 -+ extensions |= blackfriday.EXTENSION_NO_INTRA_EMPHASIS -+ extensions |= blackfriday.EXTENSION_TABLES -+ extensions |= blackfriday.EXTENSION_FENCED_CODE -+ extensions |= blackfriday.EXTENSION_AUTOLINK -+ extensions |= blackfriday.EXTENSION_SPACE_HEADERS -+ extensions |= blackfriday.EXTENSION_FOOTNOTES -+ extensions |= blackfriday.EXTENSION_TITLEBLOCK -+ -+ out := blackfriday.Markdown(doc, renderer, extensions) -+ -+ outFile, err := os.Create(*outFilePath) -+ if err != nil { -+ fmt.Println(err) -+ os.Exit(1) -+ } -+ defer outFile.Close() -+ _, err = outFile.Write(out) -+ if err != nil { -+ fmt.Println(err) -+ os.Exit(1) -+ } -+} -diff --git a/vendor/src/github.com/russross/blackfriday/.travis.yml b/vendor/src/github.com/russross/blackfriday/.travis.yml -new file mode 100644 -index 0000000..4dd7a1c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/.travis.yml -@@ -0,0 +1,17 @@ -+# Travis CI (http://travis-ci.org/) is a continuous integration service for -+# open source projects. This file configures it to run unit tests for -+# blackfriday. -+ -+language: go -+ -+go: -+ - 1.2 -+ - 1.3 -+ - 1.4 -+ -+install: -+ - go get -d -t -v ./... -+ - go build -v ./... -+ -+script: -+ - go test -v ./... -diff --git a/vendor/src/github.com/russross/blackfriday/LICENSE.txt b/vendor/src/github.com/russross/blackfriday/LICENSE.txt -new file mode 100644 -index 0000000..2885af3 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/LICENSE.txt -@@ -0,0 +1,29 @@ -+Blackfriday is distributed under the Simplified BSD License: -+ -+> Copyright © 2011 Russ Ross -+> All rights reserved. -+> -+> Redistribution and use in source and binary forms, with or without -+> modification, are permitted provided that the following conditions -+> are met: -+> -+> 1. Redistributions of source code must retain the above copyright -+> notice, this list of conditions and the following disclaimer. -+> -+> 2. Redistributions in binary form must reproduce the above -+> copyright notice, this list of conditions and the following -+> disclaimer in the documentation and/or other materials provided with -+> the distribution. -+> -+> THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -+> "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+> LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -+> FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -+> COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -+> INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -+> BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -+> LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -+> CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -+> LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -+> ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -+> POSSIBILITY OF SUCH DAMAGE. -diff --git a/vendor/src/github.com/russross/blackfriday/README.md b/vendor/src/github.com/russross/blackfriday/README.md -new file mode 100644 -index 0000000..1bb985d ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/README.md -@@ -0,0 +1,246 @@ -+Blackfriday [](https://travis-ci.org/russross/blackfriday) -+=========== -+ -+Blackfriday is a [Markdown][1] processor implemented in [Go][2]. It -+is paranoid about its input (so you can safely feed it user-supplied -+data), it is fast, it supports common extensions (tables, smart -+punctuation substitutions, etc.), and it is safe for all utf-8 -+(unicode) input. -+ -+HTML output is currently supported, along with Smartypants -+extensions. An experimental LaTeX output engine is also included. -+ -+It started as a translation from C of [Sundown][3]. -+ -+ -+Installation -+------------ -+ -+Blackfriday is compatible with Go 1. If you are using an older -+release of Go, consider using v1.1 of blackfriday, which was based -+on the last stable release of Go prior to Go 1. You can find it as a -+tagged commit on github. -+ -+With Go 1 and git installed: -+ -+ go get github.com/russross/blackfriday -+ -+will download, compile, and install the package into your `$GOPATH` -+directory hierarchy. Alternatively, you can achieve the same if you -+import it into a project: -+ -+ import "github.com/russross/blackfriday" -+ -+and `go get` without parameters. -+ -+Usage -+----- -+ -+For basic usage, it is as simple as getting your input into a byte -+slice and calling: -+ -+ output := blackfriday.MarkdownBasic(input) -+ -+This renders it with no extensions enabled. To get a more useful -+feature set, use this instead: -+ -+ output := blackfriday.MarkdownCommon(input) -+ -+### Sanitize untrusted content -+ -+Blackfriday itself does nothing to protect against malicious content. If you are -+dealing with user-supplied markdown, we recommend running blackfriday's output -+through HTML sanitizer such as -+[Bluemonday](https://github.com/microcosm-cc/bluemonday). -+ -+Here's an example of simple usage of blackfriday together with bluemonday: -+ -+``` go -+import ( -+ "github.com/microcosm-cc/bluemonday" -+ "github.com/russross/blackfriday" -+) -+ -+// ... -+unsafe := blackfriday.MarkdownCommon(input) -+html := bluemonday.UGCPolicy().SanitizeBytes(unsafe) -+``` -+ -+### Custom options -+ -+If you want to customize the set of options, first get a renderer -+(currently either the HTML or LaTeX output engines), then use it to -+call the more general `Markdown` function. For examples, see the -+implementations of `MarkdownBasic` and `MarkdownCommon` in -+`markdown.go`. -+ -+You can also check out `blackfriday-tool` for a more complete example -+of how to use it. Download and install it using: -+ -+ go get github.com/russross/blackfriday-tool -+ -+This is a simple command-line tool that allows you to process a -+markdown file using a standalone program. You can also browse the -+source directly on github if you are just looking for some example -+code: -+ -+* <http://github.com/russross/blackfriday-tool> -+ -+Note that if you have not already done so, installing -+`blackfriday-tool` will be sufficient to download and install -+blackfriday in addition to the tool itself. The tool binary will be -+installed in `$GOPATH/bin`. This is a statically-linked binary that -+can be copied to wherever you need it without worrying about -+dependencies and library versions. -+ -+ -+Features -+-------- -+ -+All features of Sundown are supported, including: -+ -+* **Compatibility**. The Markdown v1.0.3 test suite passes with -+ the `--tidy` option. Without `--tidy`, the differences are -+ mostly in whitespace and entity escaping, where blackfriday is -+ more consistent and cleaner. -+ -+* **Common extensions**, including table support, fenced code -+ blocks, autolinks, strikethroughs, non-strict emphasis, etc. -+ -+* **Safety**. Blackfriday is paranoid when parsing, making it safe -+ to feed untrusted user input without fear of bad things -+ happening. The test suite stress tests this and there are no -+ known inputs that make it crash. If you find one, please let me -+ know and send me the input that does it. -+ -+ NOTE: "safety" in this context means *runtime safety only*. In order to -+ protect yourself agains JavaScript injection in untrusted content, see -+ [this example](https://github.com/russross/blackfriday#sanitize-untrusted-content). -+ -+* **Fast processing**. It is fast enough to render on-demand in -+ most web applications without having to cache the output. -+ -+* **Thread safety**. You can run multiple parsers in different -+ goroutines without ill effect. There is no dependence on global -+ shared state. -+ -+* **Minimal dependencies**. Blackfriday only depends on standard -+ library packages in Go. The source code is pretty -+ self-contained, so it is easy to add to any project, including -+ Google App Engine projects. -+ -+* **Standards compliant**. Output successfully validates using the -+ W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional. -+ -+ -+Extensions -+---------- -+ -+In addition to the standard markdown syntax, this package -+implements the following extensions: -+ -+* **Intra-word emphasis supression**. The `_` character is -+ commonly used inside words when discussing code, so having -+ markdown interpret it as an emphasis command is usually the -+ wrong thing. Blackfriday lets you treat all emphasis markers as -+ normal characters when they occur inside a word. -+ -+* **Tables**. Tables can be created by drawing them in the input -+ using a simple syntax: -+ -+ ``` -+ Name | Age -+ --------|------ -+ Bob | 27 -+ Alice | 23 -+ ``` -+ -+* **Fenced code blocks**. In addition to the normal 4-space -+ indentation to mark code blocks, you can explicitly mark them -+ and supply a language (to make syntax highlighting simple). Just -+ mark it like this: -+ -+ ``` go -+ func getTrue() bool { -+ return true -+ } -+ ``` -+ -+ You can use 3 or more backticks to mark the beginning of the -+ block, and the same number to mark the end of the block. -+ -+* **Autolinking**. Blackfriday can find URLs that have not been -+ explicitly marked as links and turn them into links. -+ -+* **Strikethrough**. Use two tildes (`~~`) to mark text that -+ should be crossed out. -+ -+* **Hard line breaks**. With this extension enabled (it is off by -+ default in the `MarkdownBasic` and `MarkdownCommon` convenience -+ functions), newlines in the input translate into line breaks in -+ the output. -+ -+* **Smart quotes**. Smartypants-style punctuation substitution is -+ supported, turning normal double- and single-quote marks into -+ curly quotes, etc. -+ -+* **LaTeX-style dash parsing** is an additional option, where `--` -+ is translated into `–`, and `---` is translated into -+ `—`. This differs from most smartypants processors, which -+ turn a single hyphen into an ndash and a double hyphen into an -+ mdash. -+ -+* **Smart fractions**, where anything that looks like a fraction -+ is translated into suitable HTML (instead of just a few special -+ cases like most smartypant processors). For example, `4/5` -+ becomes `<sup>4</sup>⁄<sub>5</sub>`, which renders as -+ <sup>4</sup>⁄<sub>5</sub>. -+ -+ -+Other renderers -+--------------- -+ -+Blackfriday is structured to allow alternative rendering engines. Here -+are a few of note: -+ -+* [github_flavored_markdown](https://godoc.org/github.com/shurcooL/go/github_flavored_markdown): -+ provides a GitHub Flavored Markdown renderer with fenced code block -+ highlighting, clickable header anchor links. -+ -+ It's not customizable, and its goal is to produce HTML output -+ equivalent to the [GitHub Markdown API endpoint](https://developer.github.com/v3/markdown/#render-a-markdown-document-in-raw-mode), -+ except the rendering is performed locally. -+ -+* [markdownfmt](https://github.com/shurcooL/markdownfmt): like gofmt, -+ but for markdown. -+ -+* LaTeX output: renders output as LaTeX. This is currently part of the -+ main Blackfriday repository, but may be split into its own project -+ in the future. If you are interested in owning and maintaining the -+ LaTeX output component, please be in touch. -+ -+ It renders some basic documents, but is only experimental at this -+ point. In particular, it does not do any inline escaping, so input -+ that happens to look like LaTeX code will be passed through without -+ modification. -+ -+ -+Todo -+---- -+ -+* More unit testing -+* Improve unicode support. It does not understand all unicode -+ rules (about what constitutes a letter, a punctuation symbol, -+ etc.), so it may fail to detect word boundaries correctly in -+ some instances. It is safe on all utf-8 input. -+ -+ -+License -+------- -+ -+[Blackfriday is distributed under the Simplified BSD License](LICENSE.txt) -+ -+ -+ [1]: http://daringfireball.net/projects/markdown/ "Markdown" -+ [2]: http://golang.org/ "Go Language" -+ [3]: https://github.com/vmg/sundown "Sundown" -diff --git a/vendor/src/github.com/russross/blackfriday/block.go b/vendor/src/github.com/russross/blackfriday/block.go -new file mode 100644 -index 0000000..59c6d28 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/block.go -@@ -0,0 +1,1339 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// Functions to parse block-level elements. -+// -+ -+package blackfriday -+ -+import ( -+ "bytes" -+ -+ "github.com/shurcooL/sanitized_anchor_name" -+) -+ -+// Parse block-level data. -+// Note: this function and many that it calls assume that -+// the input buffer ends with a newline. -+func (p *parser) block(out *bytes.Buffer, data []byte) { -+ if len(data) == 0 || data[len(data)-1] != '\n' { -+ panic("block input is missing terminating newline") -+ } -+ -+ // this is called recursively: enforce a maximum depth -+ if p.nesting >= p.maxNesting { -+ return -+ } -+ p.nesting++ -+ -+ // parse out one block-level construct at a time -+ for len(data) > 0 { -+ // prefixed header: -+ // -+ // # Header 1 -+ // ## Header 2 -+ // ... -+ // ###### Header 6 -+ if p.isPrefixHeader(data) { -+ data = data[p.prefixHeader(out, data):] -+ continue -+ } -+ -+ // block of preformatted HTML: -+ // -+ // <div> -+ // ... -+ // </div> -+ if data[0] == '<' { -+ if i := p.html(out, data, true); i > 0 { -+ data = data[i:] -+ continue -+ } -+ } -+ -+ // title block -+ // -+ // % stuff -+ // % more stuff -+ // % even more stuff -+ if p.flags&EXTENSION_TITLEBLOCK != 0 { -+ if data[0] == '%' { -+ if i := p.titleBlock(out, data, true); i > 0 { -+ data = data[i:] -+ continue -+ } -+ } -+ } -+ -+ // blank lines. note: returns the # of bytes to skip -+ if i := p.isEmpty(data); i > 0 { -+ data = data[i:] -+ continue -+ } -+ -+ // indented code block: -+ // -+ // func max(a, b int) int { -+ // if a > b { -+ // return a -+ // } -+ // return b -+ // } -+ if p.codePrefix(data) > 0 { -+ data = data[p.code(out, data):] -+ continue -+ } -+ -+ // fenced code block: -+ // -+ // ``` go -+ // func fact(n int) int { -+ // if n <= 1 { -+ // return n -+ // } -+ // return n * fact(n-1) -+ // } -+ // ``` -+ if p.flags&EXTENSION_FENCED_CODE != 0 { -+ if i := p.fencedCode(out, data, true); i > 0 { -+ data = data[i:] -+ continue -+ } -+ } -+ -+ // horizontal rule: -+ // -+ // ------ -+ // or -+ // ****** -+ // or -+ // ______ -+ if p.isHRule(data) { -+ p.r.HRule(out) -+ var i int -+ for i = 0; data[i] != '\n'; i++ { -+ } -+ data = data[i:] -+ continue -+ } -+ -+ // block quote: -+ // -+ // > A big quote I found somewhere -+ // > on the web -+ if p.quotePrefix(data) > 0 { -+ data = data[p.quote(out, data):] -+ continue -+ } -+ -+ // table: -+ // -+ // Name | Age | Phone -+ // ------|-----|--------- -+ // Bob | 31 | 555-1234 -+ // Alice | 27 | 555-4321 -+ if p.flags&EXTENSION_TABLES != 0 { -+ if i := p.table(out, data); i > 0 { -+ data = data[i:] -+ continue -+ } -+ } -+ -+ // an itemized/unordered list: -+ // -+ // * Item 1 -+ // * Item 2 -+ // -+ // also works with + or - -+ if p.uliPrefix(data) > 0 { -+ data = data[p.list(out, data, 0):] -+ continue -+ } -+ -+ // a numbered/ordered list: -+ // -+ // 1. Item 1 -+ // 2. Item 2 -+ if p.oliPrefix(data) > 0 { -+ data = data[p.list(out, data, LIST_TYPE_ORDERED):] -+ continue -+ } -+ -+ // anything else must look like a normal paragraph -+ // note: this finds underlined headers, too -+ data = data[p.paragraph(out, data):] -+ } -+ -+ p.nesting-- -+} -+ -+func (p *parser) isPrefixHeader(data []byte) bool { -+ if data[0] != '#' { -+ return false -+ } -+ -+ if p.flags&EXTENSION_SPACE_HEADERS != 0 { -+ level := 0 -+ for level < 6 && data[level] == '#' { -+ level++ -+ } -+ if data[level] != ' ' { -+ return false -+ } -+ } -+ return true -+} -+ -+func (p *parser) prefixHeader(out *bytes.Buffer, data []byte) int { -+ level := 0 -+ for level < 6 && data[level] == '#' { -+ level++ -+ } -+ i, end := 0, 0 -+ for i = level; data[i] == ' '; i++ { -+ } -+ for end = i; data[end] != '\n'; end++ { -+ } -+ skip := end -+ id := "" -+ if p.flags&EXTENSION_HEADER_IDS != 0 { -+ j, k := 0, 0 -+ // find start/end of header id -+ for j = i; j < end-1 && (data[j] != '{' || data[j+1] != '#'); j++ { -+ } -+ for k = j + 1; k < end && data[k] != '}'; k++ { -+ } -+ // extract header id iff found -+ if j < end && k < end { -+ id = string(data[j+2 : k]) -+ end = j -+ skip = k + 1 -+ for end > 0 && data[end-1] == ' ' { -+ end-- -+ } -+ } -+ } -+ for end > 0 && data[end-1] == '#' { -+ end-- -+ } -+ for end > 0 && data[end-1] == ' ' { -+ end-- -+ } -+ if end > i { -+ if id == "" && p.flags&EXTENSION_AUTO_HEADER_IDS != 0 { -+ id = sanitized_anchor_name.Create(string(data[i:end])) -+ } -+ work := func() bool { -+ p.inline(out, data[i:end]) -+ return true -+ } -+ p.r.Header(out, work, level, id) -+ } -+ return skip -+} -+ -+func (p *parser) isUnderlinedHeader(data []byte) int { -+ // test of level 1 header -+ if data[0] == '=' { -+ i := 1 -+ for data[i] == '=' { -+ i++ -+ } -+ for data[i] == ' ' { -+ i++ -+ } -+ if data[i] == '\n' { -+ return 1 -+ } else { -+ return 0 -+ } -+ } -+ -+ // test of level 2 header -+ if data[0] == '-' { -+ i := 1 -+ for data[i] == '-' { -+ i++ -+ } -+ for data[i] == ' ' { -+ i++ -+ } -+ if data[i] == '\n' { -+ return 2 -+ } else { -+ return 0 -+ } -+ } -+ -+ return 0 -+} -+ -+func (p *parser) titleBlock(out *bytes.Buffer, data []byte, doRender bool) int { -+ if data[0] != '%' { -+ return 0 -+ } -+ splitData := bytes.Split(data, []byte("\n")) -+ var i int -+ for idx, b := range splitData { -+ if !bytes.HasPrefix(b, []byte("%")) { -+ i = idx // - 1 -+ break -+ } -+ } -+ -+ data = bytes.Join(splitData[0:i], []byte("\n")) -+ p.r.TitleBlock(out, data) -+ -+ return len(data) -+} -+ -+func (p *parser) html(out *bytes.Buffer, data []byte, doRender bool) int { -+ var i, j int -+ -+ // identify the opening tag -+ if data[0] != '<' { -+ return 0 -+ } -+ curtag, tagfound := p.htmlFindTag(data[1:]) -+ -+ // handle special cases -+ if !tagfound { -+ // check for an HTML comment -+ if size := p.htmlComment(out, data, doRender); size > 0 { -+ return size -+ } -+ -+ // check for an <hr> tag -+ if size := p.htmlHr(out, data, doRender); size > 0 { -+ return size -+ } -+ -+ // no special case recognized -+ return 0 -+ } -+ -+ // look for an unindented matching closing tag -+ // followed by a blank line -+ found := false -+ /* -+ closetag := []byte("\n</" + curtag + ">") -+ j = len(curtag) + 1 -+ for !found { -+ // scan for a closing tag at the beginning of a line -+ if skip := bytes.Index(data[j:], closetag); skip >= 0 { -+ j += skip + len(closetag) -+ } else { -+ break -+ } -+ -+ // see if it is the only thing on the line -+ if skip := p.isEmpty(data[j:]); skip > 0 { -+ // see if it is followed by a blank line/eof -+ j += skip -+ if j >= len(data) { -+ found = true -+ i = j -+ } else { -+ if skip := p.isEmpty(data[j:]); skip > 0 { -+ j += skip -+ found = true -+ i = j -+ } -+ } -+ } -+ } -+ */ -+ -+ // if not found, try a second pass looking for indented match -+ // but not if tag is "ins" or "del" (following original Markdown.pl) -+ if !found && curtag != "ins" && curtag != "del" { -+ i = 1 -+ for i < len(data) { -+ i++ -+ for i < len(data) && !(data[i-1] == '<' && data[i] == '/') { -+ i++ -+ } -+ -+ if i+2+len(curtag) >= len(data) { -+ break -+ } -+ -+ j = p.htmlFindEnd(curtag, data[i-1:]) -+ -+ if j > 0 { -+ i += j - 1 -+ found = true -+ break -+ } -+ } -+ } -+ -+ if !found { -+ return 0 -+ } -+ -+ // the end of the block has been found -+ if doRender { -+ // trim newlines -+ end := i -+ for end > 0 && data[end-1] == '\n' { -+ end-- -+ } -+ p.r.BlockHtml(out, data[:end]) -+ } -+ -+ return i -+} -+ -+// HTML comment, lax form -+func (p *parser) htmlComment(out *bytes.Buffer, data []byte, doRender bool) int { -+ if data[0] != '<' || data[1] != '!' || data[2] != '-' || data[3] != '-' { -+ return 0 -+ } -+ -+ i := 5 -+ -+ // scan for an end-of-comment marker, across lines if necessary -+ for i < len(data) && !(data[i-2] == '-' && data[i-1] == '-' && data[i] == '>') { -+ i++ -+ } -+ i++ -+ -+ // no end-of-comment marker -+ if i >= len(data) { -+ return 0 -+ } -+ -+ // needs to end with a blank line -+ if j := p.isEmpty(data[i:]); j > 0 { -+ size := i + j -+ if doRender { -+ // trim trailing newlines -+ end := size -+ for end > 0 && data[end-1] == '\n' { -+ end-- -+ } -+ p.r.BlockHtml(out, data[:end]) -+ } -+ return size -+ } -+ -+ return 0 -+} -+ -+// HR, which is the only self-closing block tag considered -+func (p *parser) htmlHr(out *bytes.Buffer, data []byte, doRender bool) int { -+ if data[0] != '<' || (data[1] != 'h' && data[1] != 'H') || (data[2] != 'r' && data[2] != 'R') { -+ return 0 -+ } -+ if data[3] != ' ' && data[3] != '/' && data[3] != '>' { -+ // not an <hr> tag after all; at least not a valid one -+ return 0 -+ } -+ -+ i := 3 -+ for data[i] != '>' && data[i] != '\n' { -+ i++ -+ } -+ -+ if data[i] == '>' { -+ i++ -+ if j := p.isEmpty(data[i:]); j > 0 { -+ size := i + j -+ if doRender { -+ // trim newlines -+ end := size -+ for end > 0 && data[end-1] == '\n' { -+ end-- -+ } -+ p.r.BlockHtml(out, data[:end]) -+ } -+ return size -+ } -+ } -+ -+ return 0 -+} -+ -+func (p *parser) htmlFindTag(data []byte) (string, bool) { -+ i := 0 -+ for isalnum(data[i]) { -+ i++ -+ } -+ key := string(data[:i]) -+ if blockTags[key] { -+ return key, true -+ } -+ return "", false -+} -+ -+func (p *parser) htmlFindEnd(tag string, data []byte) int { -+ // assume data[0] == '<' && data[1] == '/' already tested -+ -+ // check if tag is a match -+ closetag := []byte("</" + tag + ">") -+ if !bytes.HasPrefix(data, closetag) { -+ return 0 -+ } -+ i := len(closetag) -+ -+ // check that the rest of the line is blank -+ skip := 0 -+ if skip = p.isEmpty(data[i:]); skip == 0 { -+ return 0 -+ } -+ i += skip -+ skip = 0 -+ -+ if i >= len(data) { -+ return i -+ } -+ -+ if p.flags&EXTENSION_LAX_HTML_BLOCKS != 0 { -+ return i -+ } -+ if skip = p.isEmpty(data[i:]); skip == 0 { -+ // following line must be blank -+ return 0 -+ } -+ -+ return i + skip -+} -+ -+func (p *parser) isEmpty(data []byte) int { -+ // it is okay to call isEmpty on an empty buffer -+ if len(data) == 0 { -+ return 0 -+ } -+ -+ var i int -+ for i = 0; i < len(data) && data[i] != '\n'; i++ { -+ if data[i] != ' ' && data[i] != '\t' { -+ return 0 -+ } -+ } -+ return i + 1 -+} -+ -+func (p *parser) isHRule(data []byte) bool { -+ i := 0 -+ -+ // skip up to three spaces -+ for i < 3 && data[i] == ' ' { -+ i++ -+ } -+ -+ // look at the hrule char -+ if data[i] != '*' && data[i] != '-' && data[i] != '_' { -+ return false -+ } -+ c := data[i] -+ -+ // the whole line must be the char or whitespace -+ n := 0 -+ for data[i] != '\n' { -+ switch { -+ case data[i] == c: -+ n++ -+ case data[i] != ' ': -+ return false -+ } -+ i++ -+ } -+ -+ return n >= 3 -+} -+ -+func (p *parser) isFencedCode(data []byte, syntax **string, oldmarker string) (skip int, marker string) { -+ i, size := 0, 0 -+ skip = 0 -+ -+ // skip up to three spaces -+ for i < len(data) && i < 3 && data[i] == ' ' { -+ i++ -+ } -+ if i >= len(data) { -+ return -+ } -+ -+ // check for the marker characters: ~ or ` -+ if data[i] != '~' && data[i] != '`' { -+ return -+ } -+ -+ c := data[i] -+ -+ // the whole line must be the same char or whitespace -+ for i < len(data) && data[i] == c { -+ size++ -+ i++ -+ } -+ -+ if i >= len(data) { -+ return -+ } -+ -+ // the marker char must occur at least 3 times -+ if size < 3 { -+ return -+ } -+ marker = string(data[i-size : i]) -+ -+ // if this is the end marker, it must match the beginning marker -+ if oldmarker != "" && marker != oldmarker { -+ return -+ } -+ -+ if syntax != nil { -+ syn := 0 -+ -+ for i < len(data) && data[i] == ' ' { -+ i++ -+ } -+ -+ if i >= len(data) { -+ return -+ } -+ -+ syntaxStart := i -+ -+ if data[i] == '{' { -+ i++ -+ syntaxStart++ -+ -+ for i < len(data) && data[i] != '}' && data[i] != '\n' { -+ syn++ -+ i++ -+ } -+ -+ if i >= len(data) || data[i] != '}' { -+ return -+ } -+ -+ // strip all whitespace at the beginning and the end -+ // of the {} block -+ for syn > 0 && isspace(data[syntaxStart]) { -+ syntaxStart++ -+ syn-- -+ } -+ -+ for syn > 0 && isspace(data[syntaxStart+syn-1]) { -+ syn-- -+ } -+ -+ i++ -+ } else { -+ for i < len(data) && !isspace(data[i]) { -+ syn++ -+ i++ -+ } -+ } -+ -+ language := string(data[syntaxStart : syntaxStart+syn]) -+ *syntax = &language -+ } -+ -+ for i < len(data) && data[i] == ' ' { -+ i++ -+ } -+ if i >= len(data) || data[i] != '\n' { -+ return -+ } -+ -+ skip = i + 1 -+ return -+} -+ -+func (p *parser) fencedCode(out *bytes.Buffer, data []byte, doRender bool) int { -+ var lang *string -+ beg, marker := p.isFencedCode(data, &lang, "") -+ if beg == 0 || beg >= len(data) { -+ return 0 -+ } -+ -+ var work bytes.Buffer -+ -+ for { -+ // safe to assume beg < len(data) -+ -+ // check for the end of the code block -+ fenceEnd, _ := p.isFencedCode(data[beg:], nil, marker) -+ if fenceEnd != 0 { -+ beg += fenceEnd -+ break -+ } -+ -+ // copy the current line -+ end := beg -+ for end < len(data) && data[end] != '\n' { -+ end++ -+ } -+ end++ -+ -+ // did we reach the end of the buffer without a closing marker? -+ if end >= len(data) { -+ return 0 -+ } -+ -+ // verbatim copy to the working buffer -+ if doRender { -+ work.Write(data[beg:end]) -+ } -+ beg = end -+ } -+ -+ syntax := "" -+ if lang != nil { -+ syntax = *lang -+ } -+ -+ if doRender { -+ p.r.BlockCode(out, work.Bytes(), syntax) -+ } -+ -+ return beg -+} -+ -+func (p *parser) table(out *bytes.Buffer, data []byte) int { -+ var header bytes.Buffer -+ i, columns := p.tableHeader(&header, data) -+ if i == 0 { -+ return 0 -+ } -+ -+ var body bytes.Buffer -+ -+ for i < len(data) { -+ pipes, rowStart := 0, i -+ for ; data[i] != '\n'; i++ { -+ if data[i] == '|' { -+ pipes++ -+ } -+ } -+ -+ if pipes == 0 { -+ i = rowStart -+ break -+ } -+ -+ // include the newline in data sent to tableRow -+ i++ -+ p.tableRow(&body, data[rowStart:i], columns, false) -+ } -+ -+ p.r.Table(out, header.Bytes(), body.Bytes(), columns) -+ -+ return i -+} -+ -+// check if the specified position is preceeded by an odd number of backslashes -+func isBackslashEscaped(data []byte, i int) bool { -+ backslashes := 0 -+ for i-backslashes-1 >= 0 && data[i-backslashes-1] == '\\' { -+ backslashes++ -+ } -+ return backslashes&1 == 1 -+} -+ -+func (p *parser) tableHeader(out *bytes.Buffer, data []byte) (size int, columns []int) { -+ i := 0 -+ colCount := 1 -+ for i = 0; data[i] != '\n'; i++ { -+ if data[i] == '|' && !isBackslashEscaped(data, i) { -+ colCount++ -+ } -+ } -+ -+ // doesn't look like a table header -+ if colCount == 1 { -+ return -+ } -+ -+ // include the newline in the data sent to tableRow -+ header := data[:i+1] -+ -+ // column count ignores pipes at beginning or end of line -+ if data[0] == '|' { -+ colCount-- -+ } -+ if i > 2 && data[i-1] == '|' && !isBackslashEscaped(data, i-1) { -+ colCount-- -+ } -+ -+ columns = make([]int, colCount) -+ -+ // move on to the header underline -+ i++ -+ if i >= len(data) { -+ return -+ } -+ -+ if data[i] == '|' && !isBackslashEscaped(data, i) { -+ i++ -+ } -+ for data[i] == ' ' { -+ i++ -+ } -+ -+ // each column header is of form: / *:?-+:? *|/ with # dashes + # colons >= 3 -+ // and trailing | optional on last column -+ col := 0 -+ for data[i] != '\n' { -+ dashes := 0 -+ -+ if data[i] == ':' { -+ i++ -+ columns[col] |= TABLE_ALIGNMENT_LEFT -+ dashes++ -+ } -+ for data[i] == '-' { -+ i++ -+ dashes++ -+ } -+ if data[i] == ':' { -+ i++ -+ columns[col] |= TABLE_ALIGNMENT_RIGHT -+ dashes++ -+ } -+ for data[i] == ' ' { -+ i++ -+ } -+ -+ // end of column test is messy -+ switch { -+ case dashes < 3: -+ // not a valid column -+ return -+ -+ case data[i] == '|' && !isBackslashEscaped(data, i): -+ // marker found, now skip past trailing whitespace -+ col++ -+ i++ -+ for data[i] == ' ' { -+ i++ -+ } -+ -+ // trailing junk found after last column -+ if col >= colCount && data[i] != '\n' { -+ return -+ } -+ -+ case (data[i] != '|' || isBackslashEscaped(data, i)) && col+1 < colCount: -+ // something else found where marker was required -+ return -+ -+ case data[i] == '\n': -+ // marker is optional for the last column -+ col++ -+ -+ default: -+ // trailing junk found after last column -+ return -+ } -+ } -+ if col != colCount { -+ return -+ } -+ -+ p.tableRow(out, header, columns, true) -+ size = i + 1 -+ return -+} -+ -+func (p *parser) tableRow(out *bytes.Buffer, data []byte, columns []int, header bool) { -+ i, col := 0, 0 -+ var rowWork bytes.Buffer -+ -+ if data[i] == '|' && !isBackslashEscaped(data, i) { -+ i++ -+ } -+ -+ for col = 0; col < len(columns) && i < len(data); col++ { -+ for data[i] == ' ' { -+ i++ -+ } -+ -+ cellStart := i -+ -+ for (data[i] != '|' || isBackslashEscaped(data, i)) && data[i] != '\n' { -+ i++ -+ } -+ -+ cellEnd := i -+ -+ // skip the end-of-cell marker, possibly taking us past end of buffer -+ i++ -+ -+ for cellEnd > cellStart && data[cellEnd-1] == ' ' { -+ cellEnd-- -+ } -+ -+ var cellWork bytes.Buffer -+ p.inline(&cellWork, data[cellStart:cellEnd]) -+ -+ if header { -+ p.r.TableHeaderCell(&rowWork, cellWork.Bytes(), columns[col]) -+ } else { -+ p.r.TableCell(&rowWork, cellWork.Bytes(), columns[col]) -+ } -+ } -+ -+ // pad it out with empty columns to get the right number -+ for ; col < len(columns); col++ { -+ if header { -+ p.r.TableHeaderCell(&rowWork, nil, columns[col]) -+ } else { -+ p.r.TableCell(&rowWork, nil, columns[col]) -+ } -+ } -+ -+ // silently ignore rows with too many cells -+ -+ p.r.TableRow(out, rowWork.Bytes()) -+} -+ -+// returns blockquote prefix length -+func (p *parser) quotePrefix(data []byte) int { -+ i := 0 -+ for i < 3 && data[i] == ' ' { -+ i++ -+ } -+ if data[i] == '>' { -+ if data[i+1] == ' ' { -+ return i + 2 -+ } -+ return i + 1 -+ } -+ return 0 -+} -+ -+// parse a blockquote fragment -+func (p *parser) quote(out *bytes.Buffer, data []byte) int { -+ var raw bytes.Buffer -+ beg, end := 0, 0 -+ for beg < len(data) { -+ end = beg -+ for data[end] != '\n' { -+ end++ -+ } -+ end++ -+ -+ if pre := p.quotePrefix(data[beg:]); pre > 0 { -+ // skip the prefix -+ beg += pre -+ } else if p.isEmpty(data[beg:]) > 0 && -+ (end >= len(data) || -+ (p.quotePrefix(data[end:]) == 0 && p.isEmpty(data[end:]) == 0)) { -+ // blockquote ends with at least one blank line -+ // followed by something without a blockquote prefix -+ break -+ } -+ -+ // this line is part of the blockquote -+ raw.Write(data[beg:end]) -+ beg = end -+ } -+ -+ var cooked bytes.Buffer -+ p.block(&cooked, raw.Bytes()) -+ p.r.BlockQuote(out, cooked.Bytes()) -+ return end -+} -+ -+// returns prefix length for block code -+func (p *parser) codePrefix(data []byte) int { -+ if data[0] == ' ' && data[1] == ' ' && data[2] == ' ' && data[3] == ' ' { -+ return 4 -+ } -+ return 0 -+} -+ -+func (p *parser) code(out *bytes.Buffer, data []byte) int { -+ var work bytes.Buffer -+ -+ i := 0 -+ for i < len(data) { -+ beg := i -+ for data[i] != '\n' { -+ i++ -+ } -+ i++ -+ -+ blankline := p.isEmpty(data[beg:i]) > 0 -+ if pre := p.codePrefix(data[beg:i]); pre > 0 { -+ beg += pre -+ } else if !blankline { -+ // non-empty, non-prefixed line breaks the pre -+ i = beg -+ break -+ } -+ -+ // verbatim copy to the working buffeu -+ if blankline { -+ work.WriteByte('\n') -+ } else { -+ work.Write(data[beg:i]) -+ } -+ } -+ -+ // trim all the \n off the end of work -+ workbytes := work.Bytes() -+ eol := len(workbytes) -+ for eol > 0 && workbytes[eol-1] == '\n' { -+ eol-- -+ } -+ if eol != len(workbytes) { -+ work.Truncate(eol) -+ } -+ -+ work.WriteByte('\n') -+ -+ p.r.BlockCode(out, work.Bytes(), "") -+ -+ return i -+} -+ -+// returns unordered list item prefix -+func (p *parser) uliPrefix(data []byte) int { -+ i := 0 -+ -+ // start with up to 3 spaces -+ for i < 3 && data[i] == ' ' { -+ i++ -+ } -+ -+ // need a *, +, or - followed by a space -+ if (data[i] != '*' && data[i] != '+' && data[i] != '-') || -+ data[i+1] != ' ' { -+ return 0 -+ } -+ return i + 2 -+} -+ -+// returns ordered list item prefix -+func (p *parser) oliPrefix(data []byte) int { -+ i := 0 -+ -+ // start with up to 3 spaces -+ for i < 3 && data[i] == ' ' { -+ i++ -+ } -+ -+ // count the digits -+ start := i -+ for data[i] >= '0' && data[i] <= '9' { -+ i++ -+ } -+ -+ // we need >= 1 digits followed by a dot and a space -+ if start == i || data[i] != '.' || data[i+1] != ' ' { -+ return 0 -+ } -+ return i + 2 -+} -+ -+// parse ordered or unordered list block -+func (p *parser) list(out *bytes.Buffer, data []byte, flags int) int { -+ i := 0 -+ flags |= LIST_ITEM_BEGINNING_OF_LIST -+ work := func() bool { -+ for i < len(data) { -+ skip := p.listItem(out, data[i:], &flags) -+ i += skip -+ -+ if skip == 0 || flags&LIST_ITEM_END_OF_LIST != 0 { -+ break -+ } -+ flags &= ^LIST_ITEM_BEGINNING_OF_LIST -+ } -+ return true -+ } -+ -+ p.r.List(out, work, flags) -+ return i -+} -+ -+// Parse a single list item. -+// Assumes initial prefix is already removed if this is a sublist. -+func (p *parser) listItem(out *bytes.Buffer, data []byte, flags *int) int { -+ // keep track of the indentation of the first line -+ itemIndent := 0 -+ for itemIndent < 3 && data[itemIndent] == ' ' { -+ itemIndent++ -+ } -+ -+ i := p.uliPrefix(data) -+ if i == 0 { -+ i = p.oliPrefix(data) -+ } -+ if i == 0 { -+ return 0 -+ } -+ -+ // skip leading whitespace on first line -+ for data[i] == ' ' { -+ i++ -+ } -+ -+ // find the end of the line -+ line := i -+ for data[i-1] != '\n' { -+ i++ -+ } -+ -+ // get working buffer -+ var raw bytes.Buffer -+ -+ // put the first line into the working buffer -+ raw.Write(data[line:i]) -+ line = i -+ -+ // process the following lines -+ containsBlankLine := false -+ sublist := 0 -+ -+gatherlines: -+ for line < len(data) { -+ i++ -+ -+ // find the end of this line -+ for data[i-1] != '\n' { -+ i++ -+ } -+ -+ // if it is an empty line, guess that it is part of this item -+ // and move on to the next line -+ if p.isEmpty(data[line:i]) > 0 { -+ containsBlankLine = true -+ line = i -+ continue -+ } -+ -+ // calculate the indentation -+ indent := 0 -+ for indent < 4 && line+indent < i && data[line+indent] == ' ' { -+ indent++ -+ } -+ -+ chunk := data[line+indent : i] -+ -+ // evaluate how this line fits in -+ switch { -+ // is this a nested list item? -+ case (p.uliPrefix(chunk) > 0 && !p.isHRule(chunk)) || -+ p.oliPrefix(chunk) > 0: -+ -+ if containsBlankLine { -+ *flags |= LIST_ITEM_CONTAINS_BLOCK -+ } -+ -+ // to be a nested list, it must be indented more -+ // if not, it is the next item in the same list -+ if indent <= itemIndent { -+ break gatherlines -+ } -+ -+ // is this the first item in the the nested list? -+ if sublist == 0 { -+ sublist = raw.Len() -+ } -+ -+ // is this a nested prefix header? -+ case p.isPrefixHeader(chunk): -+ // if the header is not indented, it is not nested in the list -+ // and thus ends the list -+ if containsBlankLine && indent < 4 { -+ *flags |= LIST_ITEM_END_OF_LIST -+ break gatherlines -+ } -+ *flags |= LIST_ITEM_CONTAINS_BLOCK -+ -+ // anything following an empty line is only part -+ // of this item if it is indented 4 spaces -+ // (regardless of the indentation of the beginning of the item) -+ case containsBlankLine && indent < 4: -+ *flags |= LIST_ITEM_END_OF_LIST -+ break gatherlines -+ -+ // a blank line means this should be parsed as a block -+ case containsBlankLine: -+ raw.WriteByte('\n') -+ *flags |= LIST_ITEM_CONTAINS_BLOCK -+ } -+ -+ // if this line was preceeded by one or more blanks, -+ // re-introduce the blank into the buffer -+ if containsBlankLine { -+ containsBlankLine = false -+ raw.WriteByte('\n') -+ } -+ -+ // add the line into the working buffer without prefix -+ raw.Write(data[line+indent : i]) -+ -+ line = i -+ } -+ -+ rawBytes := raw.Bytes() -+ -+ // render the contents of the list item -+ var cooked bytes.Buffer -+ if *flags&LIST_ITEM_CONTAINS_BLOCK != 0 { -+ // intermediate render of block li -+ if sublist > 0 { -+ p.block(&cooked, rawBytes[:sublist]) -+ p.block(&cooked, rawBytes[sublist:]) -+ } else { -+ p.block(&cooked, rawBytes) -+ } -+ } else { -+ // intermediate render of inline li -+ if sublist > 0 { -+ p.inline(&cooked, rawBytes[:sublist]) -+ p.block(&cooked, rawBytes[sublist:]) -+ } else { -+ p.inline(&cooked, rawBytes) -+ } -+ } -+ -+ // render the actual list item -+ cookedBytes := cooked.Bytes() -+ parsedEnd := len(cookedBytes) -+ -+ // strip trailing newlines -+ for parsedEnd > 0 && cookedBytes[parsedEnd-1] == '\n' { -+ parsedEnd-- -+ } -+ p.r.ListItem(out, cookedBytes[:parsedEnd], *flags) -+ -+ return line -+} -+ -+// render a single paragraph that has already been parsed out -+func (p *parser) renderParagraph(out *bytes.Buffer, data []byte) { -+ if len(data) == 0 { -+ return -+ } -+ -+ // trim leading spaces -+ beg := 0 -+ for data[beg] == ' ' { -+ beg++ -+ } -+ -+ // trim trailing newline -+ end := len(data) - 1 -+ -+ // trim trailing spaces -+ for end > beg && data[end-1] == ' ' { -+ end-- -+ } -+ -+ work := func() bool { -+ p.inline(out, data[beg:end]) -+ return true -+ } -+ p.r.Paragraph(out, work) -+} -+ -+func (p *parser) paragraph(out *bytes.Buffer, data []byte) int { -+ // prev: index of 1st char of previous line -+ // line: index of 1st char of current line -+ // i: index of cursor/end of current line -+ var prev, line, i int -+ -+ // keep going until we find something to mark the end of the paragraph -+ for i < len(data) { -+ // mark the beginning of the current line -+ prev = line -+ current := data[i:] -+ line = i -+ -+ // did we find a blank line marking the end of the paragraph? -+ if n := p.isEmpty(current); n > 0 { -+ p.renderParagraph(out, data[:i]) -+ return i + n -+ } -+ -+ // an underline under some text marks a header, so our paragraph ended on prev line -+ if i > 0 { -+ if level := p.isUnderlinedHeader(current); level > 0 { -+ // render the paragraph -+ p.renderParagraph(out, data[:prev]) -+ -+ // ignore leading and trailing whitespace -+ eol := i - 1 -+ for prev < eol && data[prev] == ' ' { -+ prev++ -+ } -+ for eol > prev && data[eol-1] == ' ' { -+ eol-- -+ } -+ -+ // render the header -+ // this ugly double closure avoids forcing variables onto the heap -+ work := func(o *bytes.Buffer, pp *parser, d []byte) func() bool { -+ return func() bool { -+ pp.inline(o, d) -+ return true -+ } -+ }(out, p, data[prev:eol]) -+ -+ id := "" -+ if p.flags&EXTENSION_AUTO_HEADER_IDS != 0 { -+ id = sanitized_anchor_name.Create(string(data[prev:eol])) -+ } -+ -+ p.r.Header(out, work, level, id) -+ -+ // find the end of the underline -+ for data[i] != '\n' { -+ i++ -+ } -+ return i -+ } -+ } -+ -+ // if the next line starts a block of HTML, then the paragraph ends here -+ if p.flags&EXTENSION_LAX_HTML_BLOCKS != 0 { -+ if data[i] == '<' && p.html(out, current, false) > 0 { -+ // rewind to before the HTML block -+ p.renderParagraph(out, data[:i]) -+ return i -+ } -+ } -+ -+ // if there's a prefixed header or a horizontal rule after this, paragraph is over -+ if p.isPrefixHeader(current) || p.isHRule(current) { -+ p.renderParagraph(out, data[:i]) -+ return i -+ } -+ -+ // if there's a list after this, paragraph is over -+ if p.flags&EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK != 0 { -+ if p.uliPrefix(current) != 0 || -+ p.oliPrefix(current) != 0 || -+ p.quotePrefix(current) != 0 || -+ p.codePrefix(current) != 0 { -+ p.renderParagraph(out, data[:i]) -+ return i -+ } -+ } -+ -+ // otherwise, scan to the beginning of the next line -+ for data[i] != '\n' { -+ i++ -+ } -+ i++ -+ } -+ -+ p.renderParagraph(out, data[:i]) -+ return i -+} -diff --git a/vendor/src/github.com/russross/blackfriday/block_test.go b/vendor/src/github.com/russross/blackfriday/block_test.go -new file mode 100644 -index 0000000..b726c07 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/block_test.go -@@ -0,0 +1,1296 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// Unit tests for block parsing -+// -+ -+package blackfriday -+ -+import ( -+ "testing" -+) -+ -+func runMarkdownBlockWithRenderer(input string, extensions int, renderer Renderer) string { -+ return string(Markdown([]byte(input), renderer, extensions)) -+} -+ -+func runMarkdownBlock(input string, extensions int) string { -+ htmlFlags := 0 -+ htmlFlags |= HTML_USE_XHTML -+ -+ renderer := HtmlRenderer(htmlFlags, "", "") -+ -+ return runMarkdownBlockWithRenderer(input, extensions, renderer) -+} -+ -+func runnerWithRendererParameters(parameters HtmlRendererParameters) func(string, int) string { -+ return func(input string, extensions int) string { -+ htmlFlags := 0 -+ htmlFlags |= HTML_USE_XHTML -+ -+ renderer := HtmlRendererWithParameters(htmlFlags, "", "", parameters) -+ -+ return runMarkdownBlockWithRenderer(input, extensions, renderer) -+ } -+} -+ -+func doTestsBlock(t *testing.T, tests []string, extensions int) { -+ doTestsBlockWithRunner(t, tests, extensions, runMarkdownBlock) -+} -+ -+func doTestsBlockWithRunner(t *testing.T, tests []string, extensions int, runner func(string, int) string) { -+ // catch and report panics -+ var candidate string -+ defer func() { -+ if err := recover(); err != nil { -+ t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err) -+ } -+ }() -+ -+ for i := 0; i+1 < len(tests); i += 2 { -+ input := tests[i] -+ candidate = input -+ expected := tests[i+1] -+ actual := runner(candidate, extensions) -+ if actual != expected { -+ t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", -+ candidate, expected, actual) -+ } -+ -+ // now test every substring to stress test bounds checking -+ if !testing.Short() { -+ for start := 0; start < len(input); start++ { -+ for end := start + 1; end <= len(input); end++ { -+ candidate = input[start:end] -+ _ = runMarkdownBlock(candidate, extensions) -+ } -+ } -+ } -+ } -+} -+ -+func TestPrefixHeaderNoExtensions(t *testing.T) { -+ var tests = []string{ -+ "# Header 1\n", -+ "<h1>Header 1</h1>\n", -+ -+ "## Header 2\n", -+ "<h2>Header 2</h2>\n", -+ -+ "### Header 3\n", -+ "<h3>Header 3</h3>\n", -+ -+ "#### Header 4\n", -+ "<h4>Header 4</h4>\n", -+ -+ "##### Header 5\n", -+ "<h5>Header 5</h5>\n", -+ -+ "###### Header 6\n", -+ "<h6>Header 6</h6>\n", -+ -+ "####### Header 7\n", -+ "<h6># Header 7</h6>\n", -+ -+ "#Header 1\n", -+ "<h1>Header 1</h1>\n", -+ -+ "##Header 2\n", -+ "<h2>Header 2</h2>\n", -+ -+ "###Header 3\n", -+ "<h3>Header 3</h3>\n", -+ -+ "####Header 4\n", -+ "<h4>Header 4</h4>\n", -+ -+ "#####Header 5\n", -+ "<h5>Header 5</h5>\n", -+ -+ "######Header 6\n", -+ "<h6>Header 6</h6>\n", -+ -+ "#######Header 7\n", -+ "<h6>#Header 7</h6>\n", -+ -+ "Hello\n# Header 1\nGoodbye\n", -+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n", -+ -+ "* List\n# Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestPrefixHeaderSpaceExtension(t *testing.T) { -+ var tests = []string{ -+ "# Header 1\n", -+ "<h1>Header 1</h1>\n", -+ -+ "## Header 2\n", -+ "<h2>Header 2</h2>\n", -+ -+ "### Header 3\n", -+ "<h3>Header 3</h3>\n", -+ -+ "#### Header 4\n", -+ "<h4>Header 4</h4>\n", -+ -+ "##### Header 5\n", -+ "<h5>Header 5</h5>\n", -+ -+ "###### Header 6\n", -+ "<h6>Header 6</h6>\n", -+ -+ "####### Header 7\n", -+ "<p>####### Header 7</p>\n", -+ -+ "#Header 1\n", -+ "<p>#Header 1</p>\n", -+ -+ "##Header 2\n", -+ "<p>##Header 2</p>\n", -+ -+ "###Header 3\n", -+ "<p>###Header 3</p>\n", -+ -+ "####Header 4\n", -+ "<p>####Header 4</p>\n", -+ -+ "#####Header 5\n", -+ "<p>#####Header 5</p>\n", -+ -+ "######Header 6\n", -+ "<p>######Header 6</p>\n", -+ -+ "#######Header 7\n", -+ "<p>#######Header 7</p>\n", -+ -+ "Hello\n# Header 1\nGoodbye\n", -+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n", -+ -+ "* List\n# Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header\n* List\n", -+ "<ul>\n<li>List\n#Header</li>\n<li>List</li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS) -+} -+ -+func TestPrefixHeaderIdExtension(t *testing.T) { -+ var tests = []string{ -+ "# Header 1 {#someid}\n", -+ "<h1 id=\"someid\">Header 1</h1>\n", -+ -+ "# Header 1 {#someid} \n", -+ "<h1 id=\"someid\">Header 1</h1>\n", -+ -+ "# Header 1 {#someid}\n", -+ "<h1 id=\"someid\">Header 1</h1>\n", -+ -+ "# Header 1 {#someid\n", -+ "<h1>Header 1 {#someid</h1>\n", -+ -+ "# Header 1 {#someid\n", -+ "<h1>Header 1 {#someid</h1>\n", -+ -+ "# Header 1 {#someid}}\n", -+ "<h1 id=\"someid\">Header 1</h1>\n\n<p>}</p>\n", -+ -+ "## Header 2 {#someid}\n", -+ "<h2 id=\"someid\">Header 2</h2>\n", -+ -+ "### Header 3 {#someid}\n", -+ "<h3 id=\"someid\">Header 3</h3>\n", -+ -+ "#### Header 4 {#someid}\n", -+ "<h4 id=\"someid\">Header 4</h4>\n", -+ -+ "##### Header 5 {#someid}\n", -+ "<h5 id=\"someid\">Header 5</h5>\n", -+ -+ "###### Header 6 {#someid}\n", -+ "<h6 id=\"someid\">Header 6</h6>\n", -+ -+ "####### Header 7 {#someid}\n", -+ "<h6 id=\"someid\"># Header 7</h6>\n", -+ -+ "# Header 1 # {#someid}\n", -+ "<h1 id=\"someid\">Header 1</h1>\n", -+ -+ "## Header 2 ## {#someid}\n", -+ "<h2 id=\"someid\">Header 2</h2>\n", -+ -+ "Hello\n# Header 1\nGoodbye\n", -+ "<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n", -+ -+ "* List\n# Header {#someid}\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header {#someid}\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"someid\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header {#someid}\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1 id=\"someid\">Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_HEADER_IDS) -+} -+ -+func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) { -+ var tests = []string{ -+ "# header 1 {#someid}\n", -+ "<h1 id=\"PRE:someid:POST\">header 1</h1>\n", -+ -+ "## header 2 {#someid}\n", -+ "<h2 id=\"PRE:someid:POST\">header 2</h2>\n", -+ -+ "### header 3 {#someid}\n", -+ "<h3 id=\"PRE:someid:POST\">header 3</h3>\n", -+ -+ "#### header 4 {#someid}\n", -+ "<h4 id=\"PRE:someid:POST\">header 4</h4>\n", -+ -+ "##### header 5 {#someid}\n", -+ "<h5 id=\"PRE:someid:POST\">header 5</h5>\n", -+ -+ "###### header 6 {#someid}\n", -+ "<h6 id=\"PRE:someid:POST\">header 6</h6>\n", -+ -+ "####### header 7 {#someid}\n", -+ "<h6 id=\"PRE:someid:POST\"># header 7</h6>\n", -+ -+ "# header 1 # {#someid}\n", -+ "<h1 id=\"PRE:someid:POST\">header 1</h1>\n", -+ -+ "## header 2 ## {#someid}\n", -+ "<h2 id=\"PRE:someid:POST\">header 2</h2>\n", -+ -+ "* List\n# Header {#someid}\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:someid:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header {#someid}\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:someid:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header {#someid}\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1 id=\"PRE:someid:POST\">Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ } -+ -+ parameters := HtmlRendererParameters{ -+ HeaderIDPrefix: "PRE:", -+ HeaderIDSuffix: ":POST", -+ } -+ -+ doTestsBlockWithRunner(t, tests, EXTENSION_HEADER_IDS, runnerWithRendererParameters(parameters)) -+} -+ -+func TestPrefixAutoHeaderIdExtension(t *testing.T) { -+ var tests = []string{ -+ "# Header 1\n", -+ "<h1 id=\"header-1\">Header 1</h1>\n", -+ -+ "# Header 1 \n", -+ "<h1 id=\"header-1\">Header 1</h1>\n", -+ -+ "## Header 2\n", -+ "<h2 id=\"header-2\">Header 2</h2>\n", -+ -+ "### Header 3\n", -+ "<h3 id=\"header-3\">Header 3</h3>\n", -+ -+ "#### Header 4\n", -+ "<h4 id=\"header-4\">Header 4</h4>\n", -+ -+ "##### Header 5\n", -+ "<h5 id=\"header-5\">Header 5</h5>\n", -+ -+ "###### Header 6\n", -+ "<h6 id=\"header-6\">Header 6</h6>\n", -+ -+ "####### Header 7\n", -+ "<h6 id=\"header-7\"># Header 7</h6>\n", -+ -+ "Hello\n# Header 1\nGoodbye\n", -+ "<p>Hello</p>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<p>Goodbye</p>\n", -+ -+ "* List\n# Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"header\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"header\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1 id=\"nested-header\">Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ -+ "# Header\n\n# Header\n", -+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n", -+ -+ "# Header 1\n\n# Header 1", -+ "<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n", -+ -+ "# Header\n\n# Header 1\n\n# Header\n\n# Header", -+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header</h1>\n\n<h1 id=\"header-1-2\">Header</h1>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS) -+} -+ -+func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) { -+ var tests = []string{ -+ "# Header 1\n", -+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n", -+ -+ "# Header 1 \n", -+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n", -+ -+ "## Header 2\n", -+ "<h2 id=\"PRE:header-2:POST\">Header 2</h2>\n", -+ -+ "### Header 3\n", -+ "<h3 id=\"PRE:header-3:POST\">Header 3</h3>\n", -+ -+ "#### Header 4\n", -+ "<h4 id=\"PRE:header-4:POST\">Header 4</h4>\n", -+ -+ "##### Header 5\n", -+ "<h5 id=\"PRE:header-5:POST\">Header 5</h5>\n", -+ -+ "###### Header 6\n", -+ "<h6 id=\"PRE:header-6:POST\">Header 6</h6>\n", -+ -+ "####### Header 7\n", -+ "<h6 id=\"PRE:header-7:POST\"># Header 7</h6>\n", -+ -+ "Hello\n# Header 1\nGoodbye\n", -+ "<p>Hello</p>\n\n<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<p>Goodbye</p>\n", -+ -+ "* List\n# Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:header:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n#Header\n* List\n", -+ "<ul>\n<li><p>List</p>\n\n<h1 id=\"PRE:header:POST\">Header</h1></li>\n\n<li><p>List</p></li>\n</ul>\n", -+ -+ "* List\n * Nested list\n # Nested header\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" + -+ "<h1 id=\"PRE:nested-header:POST\">Nested header</h1></li>\n</ul></li>\n</ul>\n", -+ -+ "# Header\n\n# Header\n", -+ "<h1 id=\"PRE:header:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1:POST\">Header</h1>\n", -+ -+ "# Header 1\n\n# Header 1", -+ "<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<h1 id=\"PRE:header-1-1:POST\">Header 1</h1>\n", -+ -+ "# Header\n\n# Header 1\n\n# Header\n\n# Header", -+ "<h1 id=\"PRE:header:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1:POST\">Header 1</h1>\n\n<h1 id=\"PRE:header-1-1:POST\">Header</h1>\n\n<h1 id=\"PRE:header-1-2:POST\">Header</h1>\n", -+ } -+ -+ parameters := HtmlRendererParameters{ -+ HeaderIDPrefix: "PRE:", -+ HeaderIDSuffix: ":POST", -+ } -+ -+ doTestsBlockWithRunner(t, tests, EXTENSION_AUTO_HEADER_IDS, runnerWithRendererParameters(parameters)) -+} -+ -+func TestPrefixMultipleHeaderExtensions(t *testing.T) { -+ var tests = []string{ -+ "# Header\n\n# Header {#header}\n\n# Header 1", -+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS|EXTENSION_HEADER_IDS) -+} -+ -+func TestUnderlineHeaders(t *testing.T) { -+ var tests = []string{ -+ "Header 1\n========\n", -+ "<h1>Header 1</h1>\n", -+ -+ "Header 2\n--------\n", -+ "<h2>Header 2</h2>\n", -+ -+ "A\n=\n", -+ "<h1>A</h1>\n", -+ -+ "B\n-\n", -+ "<h2>B</h2>\n", -+ -+ "Paragraph\nHeader\n=\n", -+ "<p>Paragraph</p>\n\n<h1>Header</h1>\n", -+ -+ "Header\n===\nParagraph\n", -+ "<h1>Header</h1>\n\n<p>Paragraph</p>\n", -+ -+ "Header\n===\nAnother header\n---\n", -+ "<h1>Header</h1>\n\n<h2>Another header</h2>\n", -+ -+ " Header\n======\n", -+ "<h1>Header</h1>\n", -+ -+ " Code\n========\n", -+ "<pre><code>Code\n</code></pre>\n\n<p>========</p>\n", -+ -+ "Header with *inline*\n=====\n", -+ "<h1>Header with <em>inline</em></h1>\n", -+ -+ "* List\n * Sublist\n Not a header\n ------\n", -+ "<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n", -+ -+ "Paragraph\n\n\n\n\nHeader\n===\n", -+ "<p>Paragraph</p>\n\n<h1>Header</h1>\n", -+ -+ "Trailing space \n==== \n\n", -+ "<h1>Trailing space</h1>\n", -+ -+ "Trailing spaces\n==== \n\n", -+ "<h1>Trailing spaces</h1>\n", -+ -+ "Double underline\n=====\n=====\n", -+ "<h1>Double underline</h1>\n\n<p>=====</p>\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestUnderlineHeadersAutoIDs(t *testing.T) { -+ var tests = []string{ -+ "Header 1\n========\n", -+ "<h1 id=\"header-1\">Header 1</h1>\n", -+ -+ "Header 2\n--------\n", -+ "<h2 id=\"header-2\">Header 2</h2>\n", -+ -+ "A\n=\n", -+ "<h1 id=\"a\">A</h1>\n", -+ -+ "B\n-\n", -+ "<h2 id=\"b\">B</h2>\n", -+ -+ "Paragraph\nHeader\n=\n", -+ "<p>Paragraph</p>\n\n<h1 id=\"header\">Header</h1>\n", -+ -+ "Header\n===\nParagraph\n", -+ "<h1 id=\"header\">Header</h1>\n\n<p>Paragraph</p>\n", -+ -+ "Header\n===\nAnother header\n---\n", -+ "<h1 id=\"header\">Header</h1>\n\n<h2 id=\"another-header\">Another header</h2>\n", -+ -+ " Header\n======\n", -+ "<h1 id=\"header\">Header</h1>\n", -+ -+ "Header with *inline*\n=====\n", -+ "<h1 id=\"header-with-inline\">Header with <em>inline</em></h1>\n", -+ -+ "Paragraph\n\n\n\n\nHeader\n===\n", -+ "<p>Paragraph</p>\n\n<h1 id=\"header\">Header</h1>\n", -+ -+ "Trailing space \n==== \n\n", -+ "<h1 id=\"trailing-space\">Trailing space</h1>\n", -+ -+ "Trailing spaces\n==== \n\n", -+ "<h1 id=\"trailing-spaces\">Trailing spaces</h1>\n", -+ -+ "Double underline\n=====\n=====\n", -+ "<h1 id=\"double-underline\">Double underline</h1>\n\n<p>=====</p>\n", -+ -+ "Header\n======\n\nHeader\n======\n", -+ "<h1 id=\"header\">Header</h1>\n\n<h1 id=\"header-1\">Header</h1>\n", -+ -+ "Header 1\n========\n\nHeader 1\n========\n", -+ "<h1 id=\"header-1\">Header 1</h1>\n\n<h1 id=\"header-1-1\">Header 1</h1>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_AUTO_HEADER_IDS) -+} -+ -+func TestHorizontalRule(t *testing.T) { -+ var tests = []string{ -+ "-\n", -+ "<p>-</p>\n", -+ -+ "--\n", -+ "<p>--</p>\n", -+ -+ "---\n", -+ "<hr />\n", -+ -+ "----\n", -+ "<hr />\n", -+ -+ "*\n", -+ "<p>*</p>\n", -+ -+ "**\n", -+ "<p>**</p>\n", -+ -+ "***\n", -+ "<hr />\n", -+ -+ "****\n", -+ "<hr />\n", -+ -+ "_\n", -+ "<p>_</p>\n", -+ -+ "__\n", -+ "<p>__</p>\n", -+ -+ "___\n", -+ "<hr />\n", -+ -+ "____\n", -+ "<hr />\n", -+ -+ "-*-\n", -+ "<p>-*-</p>\n", -+ -+ "- - -\n", -+ "<hr />\n", -+ -+ "* * *\n", -+ "<hr />\n", -+ -+ "_ _ _\n", -+ "<hr />\n", -+ -+ "-----*\n", -+ "<p>-----*</p>\n", -+ -+ " ------ \n", -+ "<hr />\n", -+ -+ "Hello\n***\n", -+ "<p>Hello</p>\n\n<hr />\n", -+ -+ "---\n***\n___\n", -+ "<hr />\n\n<hr />\n\n<hr />\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestUnorderedList(t *testing.T) { -+ var tests = []string{ -+ "* Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "* Yin\n* Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "* Ting\n* Bong\n* Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "* Yin\n\n* Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "* Ting\n\n* Bong\n* Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "+ Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "+ Yin\n+ Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "+ Ting\n+ Bong\n+ Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "+ Yin\n\n+ Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "+ Ting\n\n+ Bong\n+ Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "- Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "- Yin\n- Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "- Ting\n- Bong\n- Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "- Yin\n\n- Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "- Ting\n\n- Bong\n- Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "*Hello\n", -+ "<p>*Hello</p>\n", -+ -+ "* Hello \n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "* Hello \n Next line \n", -+ "<ul>\n<li>Hello\nNext line</li>\n</ul>\n", -+ -+ "Paragraph\n* No linebreak\n", -+ "<p>Paragraph\n* No linebreak</p>\n", -+ -+ "Paragraph\n\n* Linebreak\n", -+ "<p>Paragraph</p>\n\n<ul>\n<li>Linebreak</li>\n</ul>\n", -+ -+ "* List\n * Nested list\n", -+ "<ul>\n<li>List\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n\n * Nested list\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n Second line\n\n + Nested\n", -+ "<ul>\n<li><p>List\nSecond line</p>\n\n<ul>\n<li>Nested</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n + Nested\n\n Continued\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested</li>\n</ul>\n\n<p>Continued</p></li>\n</ul>\n", -+ -+ "* List\n * shallow indent\n", -+ "<ul>\n<li>List\n\n<ul>\n<li>shallow indent</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n" + -+ " * shallow indent\n" + -+ " * part of second list\n" + -+ " * still second\n" + -+ " * almost there\n" + -+ " * third level\n", -+ "<ul>\n" + -+ "<li>List\n\n" + -+ "<ul>\n" + -+ "<li>shallow indent</li>\n" + -+ "<li>part of second list</li>\n" + -+ "<li>still second</li>\n" + -+ "<li>almost there\n\n" + -+ "<ul>\n" + -+ "<li>third level</li>\n" + -+ "</ul></li>\n" + -+ "</ul></li>\n" + -+ "</ul>\n", -+ -+ "* List\n extra indent, same paragraph\n", -+ "<ul>\n<li>List\n extra indent, same paragraph</li>\n</ul>\n", -+ -+ "* List\n\n code block\n", -+ "<ul>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ul>\n", -+ -+ "* List\n\n code block with spaces\n", -+ "<ul>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ul>\n", -+ -+ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>sublist</li>\n</ul>\n\n<p>normal text</p>\n\n<ul>\n<li>another sublist</li>\n</ul></li>\n</ul>\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestOrderedList(t *testing.T) { -+ var tests = []string{ -+ "1. Hello\n", -+ "<ol>\n<li>Hello</li>\n</ol>\n", -+ -+ "1. Yin\n2. Yang\n", -+ "<ol>\n<li>Yin</li>\n<li>Yang</li>\n</ol>\n", -+ -+ "1. Ting\n2. Bong\n3. Goo\n", -+ "<ol>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ol>\n", -+ -+ "1. Yin\n\n2. Yang\n", -+ "<ol>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ol>\n", -+ -+ "1. Ting\n\n2. Bong\n3. Goo\n", -+ "<ol>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ol>\n", -+ -+ "1 Hello\n", -+ "<p>1 Hello</p>\n", -+ -+ "1.Hello\n", -+ "<p>1.Hello</p>\n", -+ -+ "1. Hello \n", -+ "<ol>\n<li>Hello</li>\n</ol>\n", -+ -+ "1. Hello \n Next line \n", -+ "<ol>\n<li>Hello\nNext line</li>\n</ol>\n", -+ -+ "Paragraph\n1. No linebreak\n", -+ "<p>Paragraph\n1. No linebreak</p>\n", -+ -+ "Paragraph\n\n1. Linebreak\n", -+ "<p>Paragraph</p>\n\n<ol>\n<li>Linebreak</li>\n</ol>\n", -+ -+ "1. List\n 1. Nested list\n", -+ "<ol>\n<li>List\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n\n 1. Nested list\n", -+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n Second line\n\n 1. Nested\n", -+ "<ol>\n<li><p>List\nSecond line</p>\n\n<ol>\n<li>Nested</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n 1. Nested\n\n Continued\n", -+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested</li>\n</ol>\n\n<p>Continued</p></li>\n</ol>\n", -+ -+ "1. List\n 1. shallow indent\n", -+ "<ol>\n<li>List\n\n<ol>\n<li>shallow indent</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n" + -+ " 1. shallow indent\n" + -+ " 2. part of second list\n" + -+ " 3. still second\n" + -+ " 4. almost there\n" + -+ " 1. third level\n", -+ "<ol>\n" + -+ "<li>List\n\n" + -+ "<ol>\n" + -+ "<li>shallow indent</li>\n" + -+ "<li>part of second list</li>\n" + -+ "<li>still second</li>\n" + -+ "<li>almost there\n\n" + -+ "<ol>\n" + -+ "<li>third level</li>\n" + -+ "</ol></li>\n" + -+ "</ol></li>\n" + -+ "</ol>\n", -+ -+ "1. List\n extra indent, same paragraph\n", -+ "<ol>\n<li>List\n extra indent, same paragraph</li>\n</ol>\n", -+ -+ "1. List\n\n code block\n", -+ "<ol>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ol>\n", -+ -+ "1. List\n\n code block with spaces\n", -+ "<ol>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ol>\n", -+ -+ "1. List\n * Mixted list\n", -+ "<ol>\n<li>List\n\n<ul>\n<li>Mixted list</li>\n</ul></li>\n</ol>\n", -+ -+ "1. List\n * Mixed list\n", -+ "<ol>\n<li>List\n\n<ul>\n<li>Mixed list</li>\n</ul></li>\n</ol>\n", -+ -+ "* Start with unordered\n 1. Ordered\n", -+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n", -+ -+ "* Start with unordered\n 1. Ordered\n", -+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n", -+ -+ "1. numbers\n1. are ignored\n", -+ "<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestPreformattedHtml(t *testing.T) { -+ var tests = []string{ -+ "<div></div>\n", -+ "<div></div>\n", -+ -+ "<div>\n</div>\n", -+ "<div>\n</div>\n", -+ -+ "<div>\n</div>\nParagraph\n", -+ "<p><div>\n</div>\nParagraph</p>\n", -+ -+ "<div class=\"foo\">\n</div>\n", -+ "<div class=\"foo\">\n</div>\n", -+ -+ "<div>\nAnything here\n</div>\n", -+ "<div>\nAnything here\n</div>\n", -+ -+ "<div>\n Anything here\n</div>\n", -+ "<div>\n Anything here\n</div>\n", -+ -+ "<div>\nAnything here\n </div>\n", -+ "<div>\nAnything here\n </div>\n", -+ -+ "<div>\nThis is *not* &proceessed\n</div>\n", -+ "<div>\nThis is *not* &proceessed\n</div>\n", -+ -+ "<faketag>\n Something\n</faketag>\n", -+ "<p><faketag>\n Something\n</faketag></p>\n", -+ -+ "<div>\n Something here\n</divv>\n", -+ "<p><div>\n Something here\n</divv></p>\n", -+ -+ "Paragraph\n<div>\nHere? >&<\n</div>\n", -+ "<p>Paragraph\n<div>\nHere? >&<\n</div></p>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n", -+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n", -+ -+ "Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n", -+ "<p>Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?</p>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<p><div>\nHow about here? >&<\n</div>\nAnd here?</p>\n", -+ -+ "Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n", -+ "<p>Paragraph\n<div>\nHere? >&<\n</div></p>\n\n<p>And here?</p>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n", -+ } -+ doTestsBlock(t, tests, 0) -+} -+ -+func TestPreformattedHtmlLax(t *testing.T) { -+ var tests = []string{ -+ "Paragraph\n<div>\nHere? >&<\n</div>\n", -+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n", -+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n", -+ -+ "Paragraph\n<div>\nHere? >&<\n</div>\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n", -+ -+ "Paragraph\n<div>\nHere? >&<\n</div>\n\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<div>\nHere? >&<\n</div>\n\n<p>And here?</p>\n", -+ -+ "Paragraph\n\n<div>\nHow about here? >&<\n</div>\n\nAnd here?\n", -+ "<p>Paragraph</p>\n\n<div>\nHow about here? >&<\n</div>\n\n<p>And here?</p>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_LAX_HTML_BLOCKS) -+} -+ -+func TestFencedCodeBlock(t *testing.T) { -+ var tests = []string{ -+ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n", -+ "<pre><code class=\"language-go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n", -+ -+ "``` c\n/* special & char < > \" escaping */\n```\n", -+ "<pre><code class=\"language-c\">/* special & char < > " escaping */\n</code></pre>\n", -+ -+ "``` c\nno *inline* processing ~~of text~~\n```\n", -+ "<pre><code class=\"language-c\">no *inline* processing ~~of text~~\n</code></pre>\n", -+ -+ "```\nNo language\n```\n", -+ "<pre><code>No language\n</code></pre>\n", -+ -+ "``` {ocaml}\nlanguage in braces\n```\n", -+ "<pre><code class=\"language-ocaml\">language in braces\n</code></pre>\n", -+ -+ "``` {ocaml} \nwith extra whitespace\n```\n", -+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n", -+ -+ "```{ ocaml }\nwith extra whitespace\n```\n", -+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n", -+ -+ "~ ~~ java\nWith whitespace\n~~~\n", -+ "<p>~ ~~ java\nWith whitespace\n~~~</p>\n", -+ -+ "~~\nonly two\n~~\n", -+ "<p>~~\nonly two\n~~</p>\n", -+ -+ "```` python\nextra\n````\n", -+ "<pre><code class=\"language-python\">extra\n</code></pre>\n", -+ -+ "~~~ perl\nthree to start, four to end\n~~~~\n", -+ "<p>~~~ perl\nthree to start, four to end\n~~~~</p>\n", -+ -+ "~~~~ perl\nfour to start, three to end\n~~~\n", -+ "<p>~~~~ perl\nfour to start, three to end\n~~~</p>\n", -+ -+ "~~~ bash\ntildes\n~~~\n", -+ "<pre><code class=\"language-bash\">tildes\n</code></pre>\n", -+ -+ "``` lisp\nno ending\n", -+ "<p>``` lisp\nno ending</p>\n", -+ -+ "~~~ lisp\nend with language\n~~~ lisp\n", -+ "<p>~~~ lisp\nend with language\n~~~ lisp</p>\n", -+ -+ "```\nmismatched begin and end\n~~~\n", -+ "<p>```\nmismatched begin and end\n~~~</p>\n", -+ -+ "~~~\nmismatched begin and end\n```\n", -+ "<p>~~~\nmismatched begin and end\n```</p>\n", -+ -+ " ``` oz\nleading spaces\n```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ "``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code>``` oz\n</code></pre>\n\n<p>leading spaces\n ```</p>\n", -+ -+ "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n", -+ "<p>Bla bla</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Bla Bla</p>\n", -+ -+ "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nAnd some text after a fenced code block", -+ "<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n", -+ -+ "`", -+ "<p>`</p>\n", -+ -+ "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n\n``` oz\nmultiple code blocks work okay\n```\n\nBla Bla\n", -+ "<p>Bla bla</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Bla Bla</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>Bla Bla</p>\n", -+ -+ "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nSome text in between\n``` oz\nmultiple code blocks work okay\n```\nAnd some text after a fenced code block", -+ "<p>Some text before a fenced code block</p>\n\n<pre><code class=\"language-oz\">code blocks breakup paragraphs\n</code></pre>\n\n<p>Some text in between</p>\n\n<pre><code class=\"language-oz\">multiple code blocks work okay\n</code></pre>\n\n<p>And some text after a fenced code block</p>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_FENCED_CODE) -+} -+ -+func TestTable(t *testing.T) { -+ var tests = []string{ -+ "a | b\n---|---\nc | d\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td>c</td>\n<td>d</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a | b\n---|--\nc | d\n", -+ "<p>a | b\n---|--\nc | d</p>\n", -+ -+ "|a|b|c|d|\n|----|----|----|---|\n|e|f|g|h|\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n<th>d</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td>e</td>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "*a*|__b__|[c](C)|d\n---|---|---|---\ne|f|g|h\n", -+ "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th><strong>b</strong></th>\n<th><a href=\"C\">c</a></th>\n<th>d</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td>e</td>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a|b|c\n---|---|---\nd|e|f\ng|h\ni|j|k|l|m\nn|o|p\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td>d</td>\n<td>e</td>\n<td>f</td>\n</tr>\n\n" + -+ "<tr>\n<td>g</td>\n<td>h</td>\n<td></td>\n</tr>\n\n" + -+ "<tr>\n<td>i</td>\n<td>j</td>\n<td>k</td>\n</tr>\n\n" + -+ "<tr>\n<td>n</td>\n<td>o</td>\n<td>p</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a|b|c\n---|---|---\n*d*|__e__|f\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td><em>d</em></td>\n<td><strong>e</strong></td>\n<td>f</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a|b|c|d\n:--|--:|:-:|---\ne|f|g|h\n", -+ "<table>\n<thead>\n<tr>\n<th align=\"left\">a</th>\n<th align=\"right\">b</th>\n" + -+ "<th align=\"center\">c</th>\n<th>d</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td align=\"left\">e</td>\n<td align=\"right\">f</td>\n" + -+ "<td align=\"center\">g</td>\n<td>h</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a|b|c\n---|---|---\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n\n<tbody>\n</tbody>\n</table>\n", -+ -+ "a| b|c | d | e\n---|---|---|---|---\nf| g|h | i |j\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n<th>d</th>\n<th>e</th>\n</tr>\n</thead>\n\n" + -+ "<tbody>\n<tr>\n<td>f</td>\n<td>g</td>\n<td>h</td>\n<td>i</td>\n<td>j</td>\n</tr>\n</tbody>\n</table>\n", -+ -+ "a|b\\|c|d\n---|---|---\nf|g\\|h|i\n", -+ "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b|c</th>\n<th>d</th>\n</tr>\n</thead>\n\n<tbody>\n<tr>\n<td>f</td>\n<td>g|h</td>\n<td>i</td>\n</tr>\n</tbody>\n</table>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_TABLES) -+} -+ -+func TestUnorderedListWith_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) { -+ var tests = []string{ -+ "* Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "* Yin\n* Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "* Ting\n* Bong\n* Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "* Yin\n\n* Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "* Ting\n\n* Bong\n* Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "+ Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "+ Yin\n+ Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "+ Ting\n+ Bong\n+ Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "+ Yin\n\n+ Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "+ Ting\n\n+ Bong\n+ Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "- Hello\n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "- Yin\n- Yang\n", -+ "<ul>\n<li>Yin</li>\n<li>Yang</li>\n</ul>\n", -+ -+ "- Ting\n- Bong\n- Goo\n", -+ "<ul>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ul>\n", -+ -+ "- Yin\n\n- Yang\n", -+ "<ul>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ul>\n", -+ -+ "- Ting\n\n- Bong\n- Goo\n", -+ "<ul>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ul>\n", -+ -+ "*Hello\n", -+ "<p>*Hello</p>\n", -+ -+ "* Hello \n", -+ "<ul>\n<li>Hello</li>\n</ul>\n", -+ -+ "* Hello \n Next line \n", -+ "<ul>\n<li>Hello\nNext line</li>\n</ul>\n", -+ -+ "Paragraph\n* No linebreak\n", -+ "<p>Paragraph</p>\n\n<ul>\n<li>No linebreak</li>\n</ul>\n", -+ -+ "Paragraph\n\n* Linebreak\n", -+ "<p>Paragraph</p>\n\n<ul>\n<li>Linebreak</li>\n</ul>\n", -+ -+ "* List\n * Nested list\n", -+ "<ul>\n<li>List\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n\n * Nested list\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested list</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n Second line\n\n + Nested\n", -+ "<ul>\n<li><p>List\nSecond line</p>\n\n<ul>\n<li>Nested</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n + Nested\n\n Continued\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>Nested</li>\n</ul>\n\n<p>Continued</p></li>\n</ul>\n", -+ -+ "* List\n * shallow indent\n", -+ "<ul>\n<li>List\n\n<ul>\n<li>shallow indent</li>\n</ul></li>\n</ul>\n", -+ -+ "* List\n" + -+ " * shallow indent\n" + -+ " * part of second list\n" + -+ " * still second\n" + -+ " * almost there\n" + -+ " * third level\n", -+ "<ul>\n" + -+ "<li>List\n\n" + -+ "<ul>\n" + -+ "<li>shallow indent</li>\n" + -+ "<li>part of second list</li>\n" + -+ "<li>still second</li>\n" + -+ "<li>almost there\n\n" + -+ "<ul>\n" + -+ "<li>third level</li>\n" + -+ "</ul></li>\n" + -+ "</ul></li>\n" + -+ "</ul>\n", -+ -+ "* List\n extra indent, same paragraph\n", -+ "<ul>\n<li>List\n extra indent, same paragraph</li>\n</ul>\n", -+ -+ "* List\n\n code block\n", -+ "<ul>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ul>\n", -+ -+ "* List\n\n code block with spaces\n", -+ "<ul>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ul>\n", -+ -+ "* List\n\n * sublist\n\n normal text\n\n * another sublist\n", -+ "<ul>\n<li><p>List</p>\n\n<ul>\n<li>sublist</li>\n</ul>\n\n<p>normal text</p>\n\n<ul>\n<li>another sublist</li>\n</ul></li>\n</ul>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK) -+} -+ -+func TestOrderedList_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) { -+ var tests = []string{ -+ "1. Hello\n", -+ "<ol>\n<li>Hello</li>\n</ol>\n", -+ -+ "1. Yin\n2. Yang\n", -+ "<ol>\n<li>Yin</li>\n<li>Yang</li>\n</ol>\n", -+ -+ "1. Ting\n2. Bong\n3. Goo\n", -+ "<ol>\n<li>Ting</li>\n<li>Bong</li>\n<li>Goo</li>\n</ol>\n", -+ -+ "1. Yin\n\n2. Yang\n", -+ "<ol>\n<li><p>Yin</p></li>\n\n<li><p>Yang</p></li>\n</ol>\n", -+ -+ "1. Ting\n\n2. Bong\n3. Goo\n", -+ "<ol>\n<li><p>Ting</p></li>\n\n<li><p>Bong</p></li>\n\n<li><p>Goo</p></li>\n</ol>\n", -+ -+ "1 Hello\n", -+ "<p>1 Hello</p>\n", -+ -+ "1.Hello\n", -+ "<p>1.Hello</p>\n", -+ -+ "1. Hello \n", -+ "<ol>\n<li>Hello</li>\n</ol>\n", -+ -+ "1. Hello \n Next line \n", -+ "<ol>\n<li>Hello\nNext line</li>\n</ol>\n", -+ -+ "Paragraph\n1. No linebreak\n", -+ "<p>Paragraph</p>\n\n<ol>\n<li>No linebreak</li>\n</ol>\n", -+ -+ "Paragraph\n\n1. Linebreak\n", -+ "<p>Paragraph</p>\n\n<ol>\n<li>Linebreak</li>\n</ol>\n", -+ -+ "1. List\n 1. Nested list\n", -+ "<ol>\n<li>List\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n\n 1. Nested list\n", -+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested list</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n Second line\n\n 1. Nested\n", -+ "<ol>\n<li><p>List\nSecond line</p>\n\n<ol>\n<li>Nested</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n 1. Nested\n\n Continued\n", -+ "<ol>\n<li><p>List</p>\n\n<ol>\n<li>Nested</li>\n</ol>\n\n<p>Continued</p></li>\n</ol>\n", -+ -+ "1. List\n 1. shallow indent\n", -+ "<ol>\n<li>List\n\n<ol>\n<li>shallow indent</li>\n</ol></li>\n</ol>\n", -+ -+ "1. List\n" + -+ " 1. shallow indent\n" + -+ " 2. part of second list\n" + -+ " 3. still second\n" + -+ " 4. almost there\n" + -+ " 1. third level\n", -+ "<ol>\n" + -+ "<li>List\n\n" + -+ "<ol>\n" + -+ "<li>shallow indent</li>\n" + -+ "<li>part of second list</li>\n" + -+ "<li>still second</li>\n" + -+ "<li>almost there\n\n" + -+ "<ol>\n" + -+ "<li>third level</li>\n" + -+ "</ol></li>\n" + -+ "</ol></li>\n" + -+ "</ol>\n", -+ -+ "1. List\n extra indent, same paragraph\n", -+ "<ol>\n<li>List\n extra indent, same paragraph</li>\n</ol>\n", -+ -+ "1. List\n\n code block\n", -+ "<ol>\n<li><p>List</p>\n\n<pre><code>code block\n</code></pre></li>\n</ol>\n", -+ -+ "1. List\n\n code block with spaces\n", -+ "<ol>\n<li><p>List</p>\n\n<pre><code> code block with spaces\n</code></pre></li>\n</ol>\n", -+ -+ "1. List\n * Mixted list\n", -+ "<ol>\n<li>List\n\n<ul>\n<li>Mixted list</li>\n</ul></li>\n</ol>\n", -+ -+ "1. List\n * Mixed list\n", -+ "<ol>\n<li>List\n\n<ul>\n<li>Mixed list</li>\n</ul></li>\n</ol>\n", -+ -+ "* Start with unordered\n 1. Ordered\n", -+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n", -+ -+ "* Start with unordered\n 1. Ordered\n", -+ "<ul>\n<li>Start with unordered\n\n<ol>\n<li>Ordered</li>\n</ol></li>\n</ul>\n", -+ -+ "1. numbers\n1. are ignored\n", -+ "<ol>\n<li>numbers</li>\n<li>are ignored</li>\n</ol>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK) -+} -+ -+func TestFencedCodeBlock_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) { -+ var tests = []string{ -+ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n", -+ "<pre><code class=\"language-go\">func foo() bool {\n\treturn true;\n}\n</code></pre>\n", -+ -+ "``` c\n/* special & char < > \" escaping */\n```\n", -+ "<pre><code class=\"language-c\">/* special & char < > " escaping */\n</code></pre>\n", -+ -+ "``` c\nno *inline* processing ~~of text~~\n```\n", -+ "<pre><code class=\"language-c\">no *inline* processing ~~of text~~\n</code></pre>\n", -+ -+ "```\nNo language\n```\n", -+ "<pre><code>No language\n</code></pre>\n", -+ -+ "``` {ocaml}\nlanguage in braces\n```\n", -+ "<pre><code class=\"language-ocaml\">language in braces\n</code></pre>\n", -+ -+ "``` {ocaml} \nwith extra whitespace\n```\n", -+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n", -+ -+ "```{ ocaml }\nwith extra whitespace\n```\n", -+ "<pre><code class=\"language-ocaml\">with extra whitespace\n</code></pre>\n", -+ -+ "~ ~~ java\nWith whitespace\n~~~\n", -+ "<p>~ ~~ java\nWith whitespace\n~~~</p>\n", -+ -+ "~~\nonly two\n~~\n", -+ "<p>~~\nonly two\n~~</p>\n", -+ -+ "```` python\nextra\n````\n", -+ "<pre><code class=\"language-python\">extra\n</code></pre>\n", -+ -+ "~~~ perl\nthree to start, four to end\n~~~~\n", -+ "<p>~~~ perl\nthree to start, four to end\n~~~~</p>\n", -+ -+ "~~~~ perl\nfour to start, three to end\n~~~\n", -+ "<p>~~~~ perl\nfour to start, three to end\n~~~</p>\n", -+ -+ "~~~ bash\ntildes\n~~~\n", -+ "<pre><code class=\"language-bash\">tildes\n</code></pre>\n", -+ -+ "``` lisp\nno ending\n", -+ "<p>``` lisp\nno ending</p>\n", -+ -+ "~~~ lisp\nend with language\n~~~ lisp\n", -+ "<p>~~~ lisp\nend with language\n~~~ lisp</p>\n", -+ -+ "```\nmismatched begin and end\n~~~\n", -+ "<p>```\nmismatched begin and end\n~~~</p>\n", -+ -+ "~~~\nmismatched begin and end\n```\n", -+ "<p>~~~\nmismatched begin and end\n```</p>\n", -+ -+ " ``` oz\nleading spaces\n```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ "``` oz\nleading spaces\n ```\n", -+ "<pre><code class=\"language-oz\">leading spaces\n</code></pre>\n", -+ -+ " ``` oz\nleading spaces\n ```\n", -+ "<pre><code>``` oz\n</code></pre>\n\n<p>leading spaces</p>\n\n<pre><code>```\n</code></pre>\n", -+ } -+ doTestsBlock(t, tests, EXTENSION_FENCED_CODE|EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK) -+} -+ -+func TestTitleBlock_EXTENSION_TITLEBLOCK(t *testing.T) { -+ var tests = []string{ -+ "% Some title\n" + -+ "% Another title line\n" + -+ "% Yep, more here too\n", -+ "<h1 class=\"title\">" + -+ "Some title\n" + -+ "Another title line\n" + -+ "Yep, more here too\n" + -+ "</h1>", -+ } -+ -+ doTestsBlock(t, tests, EXTENSION_TITLEBLOCK) -+ -+} -diff --git a/vendor/src/github.com/russross/blackfriday/html.go b/vendor/src/github.com/russross/blackfriday/html.go -new file mode 100644 -index 0000000..3655a10 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/html.go -@@ -0,0 +1,922 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// -+// HTML rendering backend -+// -+// -+ -+package blackfriday -+ -+import ( -+ "bytes" -+ "fmt" -+ "regexp" -+ "strconv" -+ "strings" -+) -+ -+// Html renderer configuration options. -+const ( -+ HTML_SKIP_HTML = 1 << iota // skip preformatted HTML blocks -+ HTML_SKIP_STYLE // skip embedded <style> elements -+ HTML_SKIP_IMAGES // skip embedded images -+ HTML_SKIP_LINKS // skip all links -+ HTML_SAFELINK // only link to trusted protocols -+ HTML_NOFOLLOW_LINKS // only link with rel="nofollow" -+ HTML_NOREFERRER_LINKS // only link with rel="noreferrer" -+ HTML_HREF_TARGET_BLANK // add a blank target -+ HTML_TOC // generate a table of contents -+ HTML_OMIT_CONTENTS // skip the main contents (for a standalone table of contents) -+ HTML_COMPLETE_PAGE // generate a complete HTML page -+ HTML_USE_XHTML // generate XHTML output instead of HTML -+ HTML_USE_SMARTYPANTS // enable smart punctuation substitutions -+ HTML_SMARTYPANTS_FRACTIONS // enable smart fractions (with HTML_USE_SMARTYPANTS) -+ HTML_SMARTYPANTS_LATEX_DASHES // enable LaTeX-style dashes (with HTML_USE_SMARTYPANTS) -+ HTML_SMARTYPANTS_ANGLED_QUOTES // enable angled double quotes (with HTML_USE_SMARTYPANTS) for double quotes rendering -+ HTML_FOOTNOTE_RETURN_LINKS // generate a link at the end of a footnote to return to the source -+) -+ -+var ( -+ alignments = []string{ -+ "left", -+ "right", -+ "center", -+ } -+ -+ // TODO: improve this regexp to catch all possible entities: -+ htmlEntity = regexp.MustCompile(`&[a-z]{2,5};`) -+) -+ -+type HtmlRendererParameters struct { -+ // Prepend this text to each relative URL. -+ AbsolutePrefix string -+ // Add this text to each footnote anchor, to ensure uniqueness. -+ FootnoteAnchorPrefix string -+ // Show this text inside the <a> tag for a footnote return link, if the -+ // HTML_FOOTNOTE_RETURN_LINKS flag is enabled. If blank, the string -+ // <sup>[return]</sup> is used. -+ FootnoteReturnLinkContents string -+ // If set, add this text to the front of each Header ID, to ensure -+ // uniqueness. -+ HeaderIDPrefix string -+ // If set, add this text to the back of each Header ID, to ensure uniqueness. -+ HeaderIDSuffix string -+} -+ -+// Html is a type that implements the Renderer interface for HTML output. -+// -+// Do not create this directly, instead use the HtmlRenderer function. -+type Html struct { -+ flags int // HTML_* options -+ closeTag string // how to end singleton tags: either " />\n" or ">\n" -+ title string // document title -+ css string // optional css file url (used with HTML_COMPLETE_PAGE) -+ -+ parameters HtmlRendererParameters -+ -+ // table of contents data -+ tocMarker int -+ headerCount int -+ currentLevel int -+ toc *bytes.Buffer -+ -+ // Track header IDs to prevent ID collision in a single generation. -+ headerIDs map[string]int -+ -+ smartypants *smartypantsRenderer -+} -+ -+const ( -+ xhtmlClose = " />\n" -+ htmlClose = ">\n" -+) -+ -+// HtmlRenderer creates and configures an Html object, which -+// satisfies the Renderer interface. -+// -+// flags is a set of HTML_* options ORed together. -+// title is the title of the document, and css is a URL for the document's -+// stylesheet. -+// title and css are only used when HTML_COMPLETE_PAGE is selected. -+func HtmlRenderer(flags int, title string, css string) Renderer { -+ return HtmlRendererWithParameters(flags, title, css, HtmlRendererParameters{}) -+} -+ -+func HtmlRendererWithParameters(flags int, title string, -+ css string, renderParameters HtmlRendererParameters) Renderer { -+ // configure the rendering engine -+ closeTag := htmlClose -+ if flags&HTML_USE_XHTML != 0 { -+ closeTag = xhtmlClose -+ } -+ -+ if renderParameters.FootnoteReturnLinkContents == "" { -+ renderParameters.FootnoteReturnLinkContents = `<sup>[return]</sup>` -+ } -+ -+ return &Html{ -+ flags: flags, -+ closeTag: closeTag, -+ title: title, -+ css: css, -+ parameters: renderParameters, -+ -+ headerCount: 0, -+ currentLevel: 0, -+ toc: new(bytes.Buffer), -+ -+ headerIDs: make(map[string]int), -+ -+ smartypants: smartypants(flags), -+ } -+} -+ -+// Using if statements is a bit faster than a switch statement. As the compiler -+// improves, this should be unnecessary this is only worthwhile because -+// attrEscape is the single largest CPU user in normal use. -+// Also tried using map, but that gave a ~3x slowdown. -+func escapeSingleChar(char byte) (string, bool) { -+ if char == '"' { -+ return """, true -+ } -+ if char == '&' { -+ return "&", true -+ } -+ if char == '<' { -+ return "<", true -+ } -+ if char == '>' { -+ return ">", true -+ } -+ return "", false -+} -+ -+func attrEscape(out *bytes.Buffer, src []byte) { -+ org := 0 -+ for i, ch := range src { -+ if entity, ok := escapeSingleChar(ch); ok { -+ if i > org { -+ // copy all the normal characters since the last escape -+ out.Write(src[org:i]) -+ } -+ org = i + 1 -+ out.WriteString(entity) -+ } -+ } -+ if org < len(src) { -+ out.Write(src[org:]) -+ } -+} -+ -+func entityEscapeWithSkip(out *bytes.Buffer, src []byte, skipRanges [][]int) { -+ end := 0 -+ for _, rang := range skipRanges { -+ attrEscape(out, src[end:rang[0]]) -+ out.Write(src[rang[0]:rang[1]]) -+ end = rang[1] -+ } -+ attrEscape(out, src[end:]) -+} -+ -+func (options *Html) GetFlags() int { -+ return options.flags -+} -+ -+func (options *Html) TitleBlock(out *bytes.Buffer, text []byte) { -+ text = bytes.TrimPrefix(text, []byte("% ")) -+ text = bytes.Replace(text, []byte("\n% "), []byte("\n"), -1) -+ out.WriteString("<h1 class=\"title\">") -+ out.Write(text) -+ out.WriteString("\n</h1>") -+} -+ -+func (options *Html) Header(out *bytes.Buffer, text func() bool, level int, id string) { -+ marker := out.Len() -+ doubleSpace(out) -+ -+ if id == "" && options.flags&HTML_TOC != 0 { -+ id = fmt.Sprintf("toc_%d", options.headerCount) -+ } -+ -+ if id != "" { -+ id = options.ensureUniqueHeaderID(id) -+ -+ if options.parameters.HeaderIDPrefix != "" { -+ id = options.parameters.HeaderIDPrefix + id -+ } -+ -+ if options.parameters.HeaderIDSuffix != "" { -+ id = id + options.parameters.HeaderIDSuffix -+ } -+ -+ out.WriteString(fmt.Sprintf("<h%d id=\"%s\">", level, id)) -+ } else { -+ out.WriteString(fmt.Sprintf("<h%d>", level)) -+ } -+ -+ tocMarker := out.Len() -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ -+ // are we building a table of contents? -+ if options.flags&HTML_TOC != 0 { -+ options.TocHeaderWithAnchor(out.Bytes()[tocMarker:], level, id) -+ } -+ -+ out.WriteString(fmt.Sprintf("</h%d>\n", level)) -+} -+ -+func (options *Html) BlockHtml(out *bytes.Buffer, text []byte) { -+ if options.flags&HTML_SKIP_HTML != 0 { -+ return -+ } -+ -+ doubleSpace(out) -+ out.Write(text) -+ out.WriteByte('\n') -+} -+ -+func (options *Html) HRule(out *bytes.Buffer) { -+ doubleSpace(out) -+ out.WriteString("<hr") -+ out.WriteString(options.closeTag) -+} -+ -+func (options *Html) BlockCode(out *bytes.Buffer, text []byte, lang string) { -+ doubleSpace(out) -+ -+ // parse out the language names/classes -+ count := 0 -+ for _, elt := range strings.Fields(lang) { -+ if elt[0] == '.' { -+ elt = elt[1:] -+ } -+ if len(elt) == 0 { -+ continue -+ } -+ if count == 0 { -+ out.WriteString("<pre><code class=\"language-") -+ } else { -+ out.WriteByte(' ') -+ } -+ attrEscape(out, []byte(elt)) -+ count++ -+ } -+ -+ if count == 0 { -+ out.WriteString("<pre><code>") -+ } else { -+ out.WriteString("\">") -+ } -+ -+ attrEscape(out, text) -+ out.WriteString("</code></pre>\n") -+} -+ -+func (options *Html) BlockQuote(out *bytes.Buffer, text []byte) { -+ doubleSpace(out) -+ out.WriteString("<blockquote>\n") -+ out.Write(text) -+ out.WriteString("</blockquote>\n") -+} -+ -+func (options *Html) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { -+ doubleSpace(out) -+ out.WriteString("<table>\n<thead>\n") -+ out.Write(header) -+ out.WriteString("</thead>\n\n<tbody>\n") -+ out.Write(body) -+ out.WriteString("</tbody>\n</table>\n") -+} -+ -+func (options *Html) TableRow(out *bytes.Buffer, text []byte) { -+ doubleSpace(out) -+ out.WriteString("<tr>\n") -+ out.Write(text) -+ out.WriteString("\n</tr>\n") -+} -+ -+func (options *Html) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { -+ doubleSpace(out) -+ switch align { -+ case TABLE_ALIGNMENT_LEFT: -+ out.WriteString("<th align=\"left\">") -+ case TABLE_ALIGNMENT_RIGHT: -+ out.WriteString("<th align=\"right\">") -+ case TABLE_ALIGNMENT_CENTER: -+ out.WriteString("<th align=\"center\">") -+ default: -+ out.WriteString("<th>") -+ } -+ -+ out.Write(text) -+ out.WriteString("</th>") -+} -+ -+func (options *Html) TableCell(out *bytes.Buffer, text []byte, align int) { -+ doubleSpace(out) -+ switch align { -+ case TABLE_ALIGNMENT_LEFT: -+ out.WriteString("<td align=\"left\">") -+ case TABLE_ALIGNMENT_RIGHT: -+ out.WriteString("<td align=\"right\">") -+ case TABLE_ALIGNMENT_CENTER: -+ out.WriteString("<td align=\"center\">") -+ default: -+ out.WriteString("<td>") -+ } -+ -+ out.Write(text) -+ out.WriteString("</td>") -+} -+ -+func (options *Html) Footnotes(out *bytes.Buffer, text func() bool) { -+ out.WriteString("<div class=\"footnotes\">\n") -+ options.HRule(out) -+ options.List(out, text, LIST_TYPE_ORDERED) -+ out.WriteString("</div>\n") -+} -+ -+func (options *Html) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { -+ if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 { -+ doubleSpace(out) -+ } -+ slug := slugify(name) -+ out.WriteString(`<li id="`) -+ out.WriteString(`fn:`) -+ out.WriteString(options.parameters.FootnoteAnchorPrefix) -+ out.Write(slug) -+ out.WriteString(`">`) -+ out.Write(text) -+ if options.flags&HTML_FOOTNOTE_RETURN_LINKS != 0 { -+ out.WriteString(` <a class="footnote-return" href="#`) -+ out.WriteString(`fnref:`) -+ out.WriteString(options.parameters.FootnoteAnchorPrefix) -+ out.Write(slug) -+ out.WriteString(`">`) -+ out.WriteString(options.parameters.FootnoteReturnLinkContents) -+ out.WriteString(`</a>`) -+ } -+ out.WriteString("</li>\n") -+} -+ -+func (options *Html) List(out *bytes.Buffer, text func() bool, flags int) { -+ marker := out.Len() -+ doubleSpace(out) -+ -+ if flags&LIST_TYPE_ORDERED != 0 { -+ out.WriteString("<ol>") -+ } else { -+ out.WriteString("<ul>") -+ } -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ if flags&LIST_TYPE_ORDERED != 0 { -+ out.WriteString("</ol>\n") -+ } else { -+ out.WriteString("</ul>\n") -+ } -+} -+ -+func (options *Html) ListItem(out *bytes.Buffer, text []byte, flags int) { -+ if flags&LIST_ITEM_CONTAINS_BLOCK != 0 || flags&LIST_ITEM_BEGINNING_OF_LIST != 0 { -+ doubleSpace(out) -+ } -+ out.WriteString("<li>") -+ out.Write(text) -+ out.WriteString("</li>\n") -+} -+ -+func (options *Html) Paragraph(out *bytes.Buffer, text func() bool) { -+ marker := out.Len() -+ doubleSpace(out) -+ -+ out.WriteString("<p>") -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ out.WriteString("</p>\n") -+} -+ -+func (options *Html) AutoLink(out *bytes.Buffer, link []byte, kind int) { -+ skipRanges := htmlEntity.FindAllIndex(link, -1) -+ if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) && kind != LINK_TYPE_EMAIL { -+ // mark it but don't link it if it is not a safe link: no smartypants -+ out.WriteString("<tt>") -+ entityEscapeWithSkip(out, link, skipRanges) -+ out.WriteString("</tt>") -+ return -+ } -+ -+ out.WriteString("<a href=\"") -+ if kind == LINK_TYPE_EMAIL { -+ out.WriteString("mailto:") -+ } else { -+ options.maybeWriteAbsolutePrefix(out, link) -+ } -+ -+ entityEscapeWithSkip(out, link, skipRanges) -+ -+ var relAttrs []string -+ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) { -+ relAttrs = append(relAttrs, "nofollow") -+ } -+ if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) { -+ relAttrs = append(relAttrs, "noreferrer") -+ } -+ if len(relAttrs) > 0 { -+ out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " "))) -+ } -+ -+ // blank target only add to external link -+ if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) { -+ out.WriteString("\" target=\"_blank") -+ } -+ -+ out.WriteString("\">") -+ -+ // Pretty print: if we get an email address as -+ // an actual URI, e.g. `mailto:foo@bar.com`, we don't -+ // want to print the `mailto:` prefix -+ switch { -+ case bytes.HasPrefix(link, []byte("mailto://")): -+ attrEscape(out, link[len("mailto://"):]) -+ case bytes.HasPrefix(link, []byte("mailto:")): -+ attrEscape(out, link[len("mailto:"):]) -+ default: -+ entityEscapeWithSkip(out, link, skipRanges) -+ } -+ -+ out.WriteString("</a>") -+} -+ -+func (options *Html) CodeSpan(out *bytes.Buffer, text []byte) { -+ out.WriteString("<code>") -+ attrEscape(out, text) -+ out.WriteString("</code>") -+} -+ -+func (options *Html) DoubleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("<strong>") -+ out.Write(text) -+ out.WriteString("</strong>") -+} -+ -+func (options *Html) Emphasis(out *bytes.Buffer, text []byte) { -+ if len(text) == 0 { -+ return -+ } -+ out.WriteString("<em>") -+ out.Write(text) -+ out.WriteString("</em>") -+} -+ -+func (options *Html) maybeWriteAbsolutePrefix(out *bytes.Buffer, link []byte) { -+ if options.parameters.AbsolutePrefix != "" && isRelativeLink(link) && link[0] != '.' { -+ out.WriteString(options.parameters.AbsolutePrefix) -+ if link[0] != '/' { -+ out.WriteByte('/') -+ } -+ } -+} -+ -+func (options *Html) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { -+ if options.flags&HTML_SKIP_IMAGES != 0 { -+ return -+ } -+ -+ out.WriteString("<img src=\"") -+ options.maybeWriteAbsolutePrefix(out, link) -+ attrEscape(out, link) -+ out.WriteString("\" alt=\"") -+ if len(alt) > 0 { -+ attrEscape(out, alt) -+ } -+ if len(title) > 0 { -+ out.WriteString("\" title=\"") -+ attrEscape(out, title) -+ } -+ -+ out.WriteByte('"') -+ out.WriteString(options.closeTag) -+ return -+} -+ -+func (options *Html) LineBreak(out *bytes.Buffer) { -+ out.WriteString("<br") -+ out.WriteString(options.closeTag) -+} -+ -+func (options *Html) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { -+ if options.flags&HTML_SKIP_LINKS != 0 { -+ // write the link text out but don't link it, just mark it with typewriter font -+ out.WriteString("<tt>") -+ attrEscape(out, content) -+ out.WriteString("</tt>") -+ return -+ } -+ -+ if options.flags&HTML_SAFELINK != 0 && !isSafeLink(link) { -+ // write the link text out but don't link it, just mark it with typewriter font -+ out.WriteString("<tt>") -+ attrEscape(out, content) -+ out.WriteString("</tt>") -+ return -+ } -+ -+ out.WriteString("<a href=\"") -+ options.maybeWriteAbsolutePrefix(out, link) -+ attrEscape(out, link) -+ if len(title) > 0 { -+ out.WriteString("\" title=\"") -+ attrEscape(out, title) -+ } -+ var relAttrs []string -+ if options.flags&HTML_NOFOLLOW_LINKS != 0 && !isRelativeLink(link) { -+ relAttrs = append(relAttrs, "nofollow") -+ } -+ if options.flags&HTML_NOREFERRER_LINKS != 0 && !isRelativeLink(link) { -+ relAttrs = append(relAttrs, "noreferrer") -+ } -+ if len(relAttrs) > 0 { -+ out.WriteString(fmt.Sprintf("\" rel=\"%s", strings.Join(relAttrs, " "))) -+ } -+ -+ // blank target only add to external link -+ if options.flags&HTML_HREF_TARGET_BLANK != 0 && !isRelativeLink(link) { -+ out.WriteString("\" target=\"_blank") -+ } -+ -+ out.WriteString("\">") -+ out.Write(content) -+ out.WriteString("</a>") -+ return -+} -+ -+func (options *Html) RawHtmlTag(out *bytes.Buffer, text []byte) { -+ if options.flags&HTML_SKIP_HTML != 0 { -+ return -+ } -+ if options.flags&HTML_SKIP_STYLE != 0 && isHtmlTag(text, "style") { -+ return -+ } -+ if options.flags&HTML_SKIP_LINKS != 0 && isHtmlTag(text, "a") { -+ return -+ } -+ if options.flags&HTML_SKIP_IMAGES != 0 && isHtmlTag(text, "img") { -+ return -+ } -+ out.Write(text) -+} -+ -+func (options *Html) TripleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("<strong><em>") -+ out.Write(text) -+ out.WriteString("</em></strong>") -+} -+ -+func (options *Html) StrikeThrough(out *bytes.Buffer, text []byte) { -+ out.WriteString("<del>") -+ out.Write(text) -+ out.WriteString("</del>") -+} -+ -+func (options *Html) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { -+ slug := slugify(ref) -+ out.WriteString(`<sup class="footnote-ref" id="`) -+ out.WriteString(`fnref:`) -+ out.WriteString(options.parameters.FootnoteAnchorPrefix) -+ out.Write(slug) -+ out.WriteString(`"><a rel="footnote" href="#`) -+ out.WriteString(`fn:`) -+ out.WriteString(options.parameters.FootnoteAnchorPrefix) -+ out.Write(slug) -+ out.WriteString(`">`) -+ out.WriteString(strconv.Itoa(id)) -+ out.WriteString(`</a></sup>`) -+} -+ -+func (options *Html) Entity(out *bytes.Buffer, entity []byte) { -+ out.Write(entity) -+} -+ -+func (options *Html) NormalText(out *bytes.Buffer, text []byte) { -+ if options.flags&HTML_USE_SMARTYPANTS != 0 { -+ options.Smartypants(out, text) -+ } else { -+ attrEscape(out, text) -+ } -+} -+ -+func (options *Html) Smartypants(out *bytes.Buffer, text []byte) { -+ smrt := smartypantsData{false, false} -+ -+ // first do normal entity escaping -+ var escaped bytes.Buffer -+ attrEscape(&escaped, text) -+ text = escaped.Bytes() -+ -+ mark := 0 -+ for i := 0; i < len(text); i++ { -+ if action := options.smartypants[text[i]]; action != nil { -+ if i > mark { -+ out.Write(text[mark:i]) -+ } -+ -+ previousChar := byte(0) -+ if i > 0 { -+ previousChar = text[i-1] -+ } -+ i += action(out, &smrt, previousChar, text[i:]) -+ mark = i + 1 -+ } -+ } -+ -+ if mark < len(text) { -+ out.Write(text[mark:]) -+ } -+} -+ -+func (options *Html) DocumentHeader(out *bytes.Buffer) { -+ if options.flags&HTML_COMPLETE_PAGE == 0 { -+ return -+ } -+ -+ ending := "" -+ if options.flags&HTML_USE_XHTML != 0 { -+ out.WriteString("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" ") -+ out.WriteString("\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n") -+ out.WriteString("<html xmlns=\"http://www.w3.org/1999/xhtml\">\n") -+ ending = " /" -+ } else { -+ out.WriteString("<!DOCTYPE html>\n") -+ out.WriteString("<html>\n") -+ } -+ out.WriteString("<head>\n") -+ out.WriteString(" <title>") -+ options.NormalText(out, []byte(options.title)) -+ out.WriteString("</title>\n") -+ out.WriteString(" <meta name=\"GENERATOR\" content=\"Blackfriday Markdown Processor v") -+ out.WriteString(VERSION) -+ out.WriteString("\"") -+ out.WriteString(ending) -+ out.WriteString(">\n") -+ out.WriteString(" <meta charset=\"utf-8\"") -+ out.WriteString(ending) -+ out.WriteString(">\n") -+ if options.css != "" { -+ out.WriteString(" <link rel=\"stylesheet\" type=\"text/css\" href=\"") -+ attrEscape(out, []byte(options.css)) -+ out.WriteString("\"") -+ out.WriteString(ending) -+ out.WriteString(">\n") -+ } -+ out.WriteString("</head>\n") -+ out.WriteString("<body>\n") -+ -+ options.tocMarker = out.Len() -+} -+ -+func (options *Html) DocumentFooter(out *bytes.Buffer) { -+ // finalize and insert the table of contents -+ if options.flags&HTML_TOC != 0 { -+ options.TocFinalize() -+ -+ // now we have to insert the table of contents into the document -+ var temp bytes.Buffer -+ -+ // start by making a copy of everything after the document header -+ temp.Write(out.Bytes()[options.tocMarker:]) -+ -+ // now clear the copied material from the main output buffer -+ out.Truncate(options.tocMarker) -+ -+ // corner case spacing issue -+ if options.flags&HTML_COMPLETE_PAGE != 0 { -+ out.WriteByte('\n') -+ } -+ -+ // insert the table of contents -+ out.WriteString("<nav>\n") -+ out.Write(options.toc.Bytes()) -+ out.WriteString("</nav>\n") -+ -+ // corner case spacing issue -+ if options.flags&HTML_COMPLETE_PAGE == 0 && options.flags&HTML_OMIT_CONTENTS == 0 { -+ out.WriteByte('\n') -+ } -+ -+ // write out everything that came after it -+ if options.flags&HTML_OMIT_CONTENTS == 0 { -+ out.Write(temp.Bytes()) -+ } -+ } -+ -+ if options.flags&HTML_COMPLETE_PAGE != 0 { -+ out.WriteString("\n</body>\n") -+ out.WriteString("</html>\n") -+ } -+ -+} -+ -+func (options *Html) TocHeaderWithAnchor(text []byte, level int, anchor string) { -+ for level > options.currentLevel { -+ switch { -+ case bytes.HasSuffix(options.toc.Bytes(), []byte("</li>\n")): -+ // this sublist can nest underneath a header -+ size := options.toc.Len() -+ options.toc.Truncate(size - len("</li>\n")) -+ -+ case options.currentLevel > 0: -+ options.toc.WriteString("<li>") -+ } -+ if options.toc.Len() > 0 { -+ options.toc.WriteByte('\n') -+ } -+ options.toc.WriteString("<ul>\n") -+ options.currentLevel++ -+ } -+ -+ for level < options.currentLevel { -+ options.toc.WriteString("</ul>") -+ if options.currentLevel > 1 { -+ options.toc.WriteString("</li>\n") -+ } -+ options.currentLevel-- -+ } -+ -+ options.toc.WriteString("<li><a href=\"#") -+ if anchor != "" { -+ options.toc.WriteString(anchor) -+ } else { -+ options.toc.WriteString("toc_") -+ options.toc.WriteString(strconv.Itoa(options.headerCount)) -+ } -+ options.toc.WriteString("\">") -+ options.headerCount++ -+ -+ options.toc.Write(text) -+ -+ options.toc.WriteString("</a></li>\n") -+} -+ -+func (options *Html) TocHeader(text []byte, level int) { -+ options.TocHeaderWithAnchor(text, level, "") -+} -+ -+func (options *Html) TocFinalize() { -+ for options.currentLevel > 1 { -+ options.toc.WriteString("</ul></li>\n") -+ options.currentLevel-- -+ } -+ -+ if options.currentLevel > 0 { -+ options.toc.WriteString("</ul>\n") -+ } -+} -+ -+func isHtmlTag(tag []byte, tagname string) bool { -+ found, _ := findHtmlTagPos(tag, tagname) -+ return found -+} -+ -+// Look for a character, but ignore it when it's in any kind of quotes, it -+// might be JavaScript -+func skipUntilCharIgnoreQuotes(html []byte, start int, char byte) int { -+ inSingleQuote := false -+ inDoubleQuote := false -+ inGraveQuote := false -+ i := start -+ for i < len(html) { -+ switch { -+ case html[i] == char && !inSingleQuote && !inDoubleQuote && !inGraveQuote: -+ return i -+ case html[i] == '\'': -+ inSingleQuote = !inSingleQuote -+ case html[i] == '"': -+ inDoubleQuote = !inDoubleQuote -+ case html[i] == '`': -+ inGraveQuote = !inGraveQuote -+ } -+ i++ -+ } -+ return start -+} -+ -+func findHtmlTagPos(tag []byte, tagname string) (bool, int) { -+ i := 0 -+ if i < len(tag) && tag[0] != '<' { -+ return false, -1 -+ } -+ i++ -+ i = skipSpace(tag, i) -+ -+ if i < len(tag) && tag[i] == '/' { -+ i++ -+ } -+ -+ i = skipSpace(tag, i) -+ j := 0 -+ for ; i < len(tag); i, j = i+1, j+1 { -+ if j >= len(tagname) { -+ break -+ } -+ -+ if strings.ToLower(string(tag[i]))[0] != tagname[j] { -+ return false, -1 -+ } -+ } -+ -+ if i == len(tag) { -+ return false, -1 -+ } -+ -+ rightAngle := skipUntilCharIgnoreQuotes(tag, i, '>') -+ if rightAngle > i { -+ return true, rightAngle -+ } -+ -+ return false, -1 -+} -+ -+func skipUntilChar(text []byte, start int, char byte) int { -+ i := start -+ for i < len(text) && text[i] != char { -+ i++ -+ } -+ return i -+} -+ -+func skipSpace(tag []byte, i int) int { -+ for i < len(tag) && isspace(tag[i]) { -+ i++ -+ } -+ return i -+} -+ -+func doubleSpace(out *bytes.Buffer) { -+ if out.Len() > 0 { -+ out.WriteByte('\n') -+ } -+} -+ -+func isRelativeLink(link []byte) (yes bool) { -+ // a tag begin with '#' -+ if link[0] == '#' { -+ return true -+ } -+ -+ // link begin with '/' but not '//', the second maybe a protocol relative link -+ if len(link) >= 2 && link[0] == '/' && link[1] != '/' { -+ return true -+ } -+ -+ // only the root '/' -+ if len(link) == 1 && link[0] == '/' { -+ return true -+ } -+ -+ // current directory : begin with "./" -+ if bytes.HasPrefix(link, []byte("./")) { -+ return true -+ } -+ -+ // parent directory : begin with "../" -+ if bytes.HasPrefix(link, []byte("../")) { -+ return true -+ } -+ -+ return false -+} -+ -+func (options *Html) ensureUniqueHeaderID(id string) string { -+ for count, found := options.headerIDs[id]; found; count, found = options.headerIDs[id] { -+ tmp := fmt.Sprintf("%s-%d", id, count+1) -+ -+ if _, tmpFound := options.headerIDs[tmp]; !tmpFound { -+ options.headerIDs[id] = count + 1 -+ id = tmp -+ } else { -+ id = id + "-1" -+ } -+ } -+ -+ if _, found := options.headerIDs[id]; !found { -+ options.headerIDs[id] = 0 -+ } -+ -+ return id -+} -diff --git a/vendor/src/github.com/russross/blackfriday/inline.go b/vendor/src/github.com/russross/blackfriday/inline.go -new file mode 100644 -index 0000000..b3ec847 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/inline.go -@@ -0,0 +1,1096 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// Functions to parse inline elements. -+// -+ -+package blackfriday -+ -+import ( -+ "bytes" -+ "regexp" -+ "strconv" -+) -+ -+var ( -+ urlRe = `((https?|ftp):\/\/|\/)[-A-Za-z0-9+&@#\/%?=~_|!:,.;\(\)]+` -+ anchorRe = regexp.MustCompile(`^(<a\shref="` + urlRe + `"(\stitle="[^"<>]+")?\s?>` + urlRe + `<\/a>)`) -+) -+ -+// Functions to parse text within a block -+// Each function returns the number of chars taken care of -+// data is the complete block being rendered -+// offset is the number of valid chars before the current cursor -+ -+func (p *parser) inline(out *bytes.Buffer, data []byte) { -+ // this is called recursively: enforce a maximum depth -+ if p.nesting >= p.maxNesting { -+ return -+ } -+ p.nesting++ -+ -+ i, end := 0, 0 -+ for i < len(data) { -+ // copy inactive chars into the output -+ for end < len(data) && p.inlineCallback[data[end]] == nil { -+ end++ -+ } -+ -+ p.r.NormalText(out, data[i:end]) -+ -+ if end >= len(data) { -+ break -+ } -+ i = end -+ -+ // call the trigger -+ handler := p.inlineCallback[data[end]] -+ if consumed := handler(p, out, data, i); consumed == 0 { -+ // no action from the callback; buffer the byte for later -+ end = i + 1 -+ } else { -+ // skip past whatever the callback used -+ i += consumed -+ end = i -+ } -+ } -+ -+ p.nesting-- -+} -+ -+// single and double emphasis parsing -+func emphasis(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ data = data[offset:] -+ c := data[0] -+ ret := 0 -+ -+ if len(data) > 2 && data[1] != c { -+ // whitespace cannot follow an opening emphasis; -+ // strikethrough only takes two characters '~~' -+ if c == '~' || isspace(data[1]) { -+ return 0 -+ } -+ if ret = helperEmphasis(p, out, data[1:], c); ret == 0 { -+ return 0 -+ } -+ -+ return ret + 1 -+ } -+ -+ if len(data) > 3 && data[1] == c && data[2] != c { -+ if isspace(data[2]) { -+ return 0 -+ } -+ if ret = helperDoubleEmphasis(p, out, data[2:], c); ret == 0 { -+ return 0 -+ } -+ -+ return ret + 2 -+ } -+ -+ if len(data) > 4 && data[1] == c && data[2] == c && data[3] != c { -+ if c == '~' || isspace(data[3]) { -+ return 0 -+ } -+ if ret = helperTripleEmphasis(p, out, data, 3, c); ret == 0 { -+ return 0 -+ } -+ -+ return ret + 3 -+ } -+ -+ return 0 -+} -+ -+func codeSpan(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ data = data[offset:] -+ -+ nb := 0 -+ -+ // count the number of backticks in the delimiter -+ for nb < len(data) && data[nb] == '`' { -+ nb++ -+ } -+ -+ // find the next delimiter -+ i, end := 0, 0 -+ for end = nb; end < len(data) && i < nb; end++ { -+ if data[end] == '`' { -+ i++ -+ } else { -+ i = 0 -+ } -+ } -+ -+ // no matching delimiter? -+ if i < nb && end >= len(data) { -+ return 0 -+ } -+ -+ // trim outside whitespace -+ fBegin := nb -+ for fBegin < end && data[fBegin] == ' ' { -+ fBegin++ -+ } -+ -+ fEnd := end - nb -+ for fEnd > fBegin && data[fEnd-1] == ' ' { -+ fEnd-- -+ } -+ -+ // render the code span -+ if fBegin != fEnd { -+ p.r.CodeSpan(out, data[fBegin:fEnd]) -+ } -+ -+ return end -+ -+} -+ -+// newline preceded by two spaces becomes <br> -+// newline without two spaces works when EXTENSION_HARD_LINE_BREAK is enabled -+func lineBreak(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ // remove trailing spaces from out -+ outBytes := out.Bytes() -+ end := len(outBytes) -+ eol := end -+ for eol > 0 && outBytes[eol-1] == ' ' { -+ eol-- -+ } -+ out.Truncate(eol) -+ -+ precededByTwoSpaces := offset >= 2 && data[offset-2] == ' ' && data[offset-1] == ' ' -+ precededByBackslash := offset >= 1 && data[offset-1] == '\\' // see http://spec.commonmark.org/0.18/#example-527 -+ precededByBackslash = precededByBackslash && p.flags&EXTENSION_BACKSLASH_LINE_BREAK != 0 -+ -+ // should there be a hard line break here? -+ if p.flags&EXTENSION_HARD_LINE_BREAK == 0 && !precededByTwoSpaces && !precededByBackslash { -+ return 0 -+ } -+ -+ if precededByBackslash && eol > 0 { -+ out.Truncate(eol - 1) -+ } -+ p.r.LineBreak(out) -+ return 1 -+} -+ -+type linkType int -+ -+const ( -+ linkNormal linkType = iota -+ linkImg -+ linkDeferredFootnote -+ linkInlineFootnote -+) -+ -+// '[': parse a link or an image or a footnote -+func link(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ // no links allowed inside regular links, footnote, and deferred footnotes -+ if p.insideLink && (offset > 0 && data[offset-1] == '[' || len(data)-1 > offset && data[offset+1] == '^') { -+ return 0 -+ } -+ -+ // [text] == regular link -+ // ![alt] == image -+ // ^[text] == inline footnote -+ // [^refId] == deferred footnote -+ var t linkType -+ if offset > 0 && data[offset-1] == '!' { -+ t = linkImg -+ } else if p.flags&EXTENSION_FOOTNOTES != 0 { -+ if offset > 0 && data[offset-1] == '^' { -+ t = linkInlineFootnote -+ } else if len(data)-1 > offset && data[offset+1] == '^' { -+ t = linkDeferredFootnote -+ } -+ } -+ -+ data = data[offset:] -+ -+ var ( -+ i = 1 -+ noteId int -+ title, link []byte -+ textHasNl = false -+ ) -+ -+ if t == linkDeferredFootnote { -+ i++ -+ } -+ -+ // look for the matching closing bracket -+ for level := 1; level > 0 && i < len(data); i++ { -+ switch { -+ case data[i] == '\n': -+ textHasNl = true -+ -+ case data[i-1] == '\\': -+ continue -+ -+ case data[i] == '[': -+ level++ -+ -+ case data[i] == ']': -+ level-- -+ if level <= 0 { -+ i-- // compensate for extra i++ in for loop -+ } -+ } -+ } -+ -+ if i >= len(data) { -+ return 0 -+ } -+ -+ txtE := i -+ i++ -+ -+ // skip any amount of whitespace or newline -+ // (this is much more lax than original markdown syntax) -+ for i < len(data) && isspace(data[i]) { -+ i++ -+ } -+ -+ // inline style link -+ switch { -+ case i < len(data) && data[i] == '(': -+ // skip initial whitespace -+ i++ -+ -+ for i < len(data) && isspace(data[i]) { -+ i++ -+ } -+ -+ linkB := i -+ -+ // look for link end: ' " ) -+ findlinkend: -+ for i < len(data) { -+ switch { -+ case data[i] == '\\': -+ i += 2 -+ -+ case data[i] == ')' || data[i] == '\'' || data[i] == '"': -+ break findlinkend -+ -+ default: -+ i++ -+ } -+ } -+ -+ if i >= len(data) { -+ return 0 -+ } -+ linkE := i -+ -+ // look for title end if present -+ titleB, titleE := 0, 0 -+ if data[i] == '\'' || data[i] == '"' { -+ i++ -+ titleB = i -+ -+ findtitleend: -+ for i < len(data) { -+ switch { -+ case data[i] == '\\': -+ i += 2 -+ -+ case data[i] == ')': -+ break findtitleend -+ -+ default: -+ i++ -+ } -+ } -+ -+ if i >= len(data) { -+ return 0 -+ } -+ -+ // skip whitespace after title -+ titleE = i - 1 -+ for titleE > titleB && isspace(data[titleE]) { -+ titleE-- -+ } -+ -+ // check for closing quote presence -+ if data[titleE] != '\'' && data[titleE] != '"' { -+ titleB, titleE = 0, 0 -+ linkE = i -+ } -+ } -+ -+ // remove whitespace at the end of the link -+ for linkE > linkB && isspace(data[linkE-1]) { -+ linkE-- -+ } -+ -+ // remove optional angle brackets around the link -+ if data[linkB] == '<' { -+ linkB++ -+ } -+ if data[linkE-1] == '>' { -+ linkE-- -+ } -+ -+ // build escaped link and title -+ if linkE > linkB { -+ link = data[linkB:linkE] -+ } -+ -+ if titleE > titleB { -+ title = data[titleB:titleE] -+ } -+ -+ i++ -+ -+ // reference style link -+ case i < len(data)-1 && data[i] == '[' && data[i+1] != '^': -+ var id []byte -+ -+ // look for the id -+ i++ -+ linkB := i -+ for i < len(data) && data[i] != ']' { -+ i++ -+ } -+ if i >= len(data) { -+ return 0 -+ } -+ linkE := i -+ -+ // find the reference -+ if linkB == linkE { -+ if textHasNl { -+ var b bytes.Buffer -+ -+ for j := 1; j < txtE; j++ { -+ switch { -+ case data[j] != '\n': -+ b.WriteByte(data[j]) -+ case data[j-1] != ' ': -+ b.WriteByte(' ') -+ } -+ } -+ -+ id = b.Bytes() -+ } else { -+ id = data[1:txtE] -+ } -+ } else { -+ id = data[linkB:linkE] -+ } -+ -+ // find the reference with matching id (ids are case-insensitive) -+ key := string(bytes.ToLower(id)) -+ lr, ok := p.refs[key] -+ if !ok { -+ return 0 -+ -+ } -+ -+ // keep link and title from reference -+ link = lr.link -+ title = lr.title -+ i++ -+ -+ // shortcut reference style link or reference or inline footnote -+ default: -+ var id []byte -+ -+ // craft the id -+ if textHasNl { -+ var b bytes.Buffer -+ -+ for j := 1; j < txtE; j++ { -+ switch { -+ case data[j] != '\n': -+ b.WriteByte(data[j]) -+ case data[j-1] != ' ': -+ b.WriteByte(' ') -+ } -+ } -+ -+ id = b.Bytes() -+ } else { -+ if t == linkDeferredFootnote { -+ id = data[2:txtE] // get rid of the ^ -+ } else { -+ id = data[1:txtE] -+ } -+ } -+ -+ key := string(bytes.ToLower(id)) -+ if t == linkInlineFootnote { -+ // create a new reference -+ noteId = len(p.notes) + 1 -+ -+ var fragment []byte -+ if len(id) > 0 { -+ if len(id) < 16 { -+ fragment = make([]byte, len(id)) -+ } else { -+ fragment = make([]byte, 16) -+ } -+ copy(fragment, slugify(id)) -+ } else { -+ fragment = append([]byte("footnote-"), []byte(strconv.Itoa(noteId))...) -+ } -+ -+ ref := &reference{ -+ noteId: noteId, -+ hasBlock: false, -+ link: fragment, -+ title: id, -+ } -+ -+ p.notes = append(p.notes, ref) -+ -+ link = ref.link -+ title = ref.title -+ } else { -+ // find the reference with matching id -+ lr, ok := p.refs[key] -+ if !ok { -+ return 0 -+ } -+ -+ if t == linkDeferredFootnote { -+ lr.noteId = len(p.notes) + 1 -+ p.notes = append(p.notes, lr) -+ } -+ -+ // keep link and title from reference -+ link = lr.link -+ // if inline footnote, title == footnote contents -+ title = lr.title -+ noteId = lr.noteId -+ } -+ -+ // rewind the whitespace -+ i = txtE + 1 -+ } -+ -+ // build content: img alt is escaped, link content is parsed -+ var content bytes.Buffer -+ if txtE > 1 { -+ if t == linkImg { -+ content.Write(data[1:txtE]) -+ } else { -+ // links cannot contain other links, so turn off link parsing temporarily -+ insideLink := p.insideLink -+ p.insideLink = true -+ p.inline(&content, data[1:txtE]) -+ p.insideLink = insideLink -+ } -+ } -+ -+ var uLink []byte -+ if t == linkNormal || t == linkImg { -+ if len(link) > 0 { -+ var uLinkBuf bytes.Buffer -+ unescapeText(&uLinkBuf, link) -+ uLink = uLinkBuf.Bytes() -+ } -+ -+ // links need something to click on and somewhere to go -+ if len(uLink) == 0 || (t == linkNormal && content.Len() == 0) { -+ return 0 -+ } -+ } -+ -+ // call the relevant rendering function -+ switch t { -+ case linkNormal: -+ p.r.Link(out, uLink, title, content.Bytes()) -+ -+ case linkImg: -+ outSize := out.Len() -+ outBytes := out.Bytes() -+ if outSize > 0 && outBytes[outSize-1] == '!' { -+ out.Truncate(outSize - 1) -+ } -+ -+ p.r.Image(out, uLink, title, content.Bytes()) -+ -+ case linkInlineFootnote: -+ outSize := out.Len() -+ outBytes := out.Bytes() -+ if outSize > 0 && outBytes[outSize-1] == '^' { -+ out.Truncate(outSize - 1) -+ } -+ -+ p.r.FootnoteRef(out, link, noteId) -+ -+ case linkDeferredFootnote: -+ p.r.FootnoteRef(out, link, noteId) -+ -+ default: -+ return 0 -+ } -+ -+ return i -+} -+ -+// '<' when tags or autolinks are allowed -+func leftAngle(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ data = data[offset:] -+ altype := LINK_TYPE_NOT_AUTOLINK -+ end := tagLength(data, &altype) -+ -+ if end > 2 { -+ if altype != LINK_TYPE_NOT_AUTOLINK { -+ var uLink bytes.Buffer -+ unescapeText(&uLink, data[1:end+1-2]) -+ if uLink.Len() > 0 { -+ p.r.AutoLink(out, uLink.Bytes(), altype) -+ } -+ } else { -+ p.r.RawHtmlTag(out, data[:end]) -+ } -+ } -+ -+ return end -+} -+ -+// '\\' backslash escape -+var escapeChars = []byte("\\`*_{}[]()#+-.!:|&<>~") -+ -+func escape(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ data = data[offset:] -+ -+ if len(data) > 1 { -+ if bytes.IndexByte(escapeChars, data[1]) < 0 { -+ return 0 -+ } -+ -+ p.r.NormalText(out, data[1:2]) -+ } -+ -+ return 2 -+} -+ -+func unescapeText(ob *bytes.Buffer, src []byte) { -+ i := 0 -+ for i < len(src) { -+ org := i -+ for i < len(src) && src[i] != '\\' { -+ i++ -+ } -+ -+ if i > org { -+ ob.Write(src[org:i]) -+ } -+ -+ if i+1 >= len(src) { -+ break -+ } -+ -+ ob.WriteByte(src[i+1]) -+ i += 2 -+ } -+} -+ -+// '&' escaped when it doesn't belong to an entity -+// valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; -+func entity(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ data = data[offset:] -+ -+ end := 1 -+ -+ if end < len(data) && data[end] == '#' { -+ end++ -+ } -+ -+ for end < len(data) && isalnum(data[end]) { -+ end++ -+ } -+ -+ if end < len(data) && data[end] == ';' { -+ end++ // real entity -+ } else { -+ return 0 // lone '&' -+ } -+ -+ p.r.Entity(out, data[:end]) -+ -+ return end -+} -+ -+func linkEndsWithEntity(data []byte, linkEnd int) bool { -+ entityRanges := htmlEntity.FindAllIndex(data[:linkEnd], -1) -+ if entityRanges != nil && entityRanges[len(entityRanges)-1][1] == linkEnd { -+ return true -+ } -+ return false -+} -+ -+func autoLink(p *parser, out *bytes.Buffer, data []byte, offset int) int { -+ // quick check to rule out most false hits on ':' -+ if p.insideLink || len(data) < offset+3 || data[offset+1] != '/' || data[offset+2] != '/' { -+ return 0 -+ } -+ -+ // Now a more expensive check to see if we're not inside an anchor element -+ anchorStart := offset -+ offsetFromAnchor := 0 -+ for anchorStart > 0 && data[anchorStart] != '<' { -+ anchorStart-- -+ offsetFromAnchor++ -+ } -+ -+ anchorStr := anchorRe.Find(data[anchorStart:]) -+ if anchorStr != nil { -+ out.Write(anchorStr[offsetFromAnchor:]) -+ return len(anchorStr) - offsetFromAnchor -+ } -+ -+ // scan backward for a word boundary -+ rewind := 0 -+ for offset-rewind > 0 && rewind <= 7 && isletter(data[offset-rewind-1]) { -+ rewind++ -+ } -+ if rewind > 6 { // longest supported protocol is "mailto" which has 6 letters -+ return 0 -+ } -+ -+ origData := data -+ data = data[offset-rewind:] -+ -+ if !isSafeLink(data) { -+ return 0 -+ } -+ -+ linkEnd := 0 -+ for linkEnd < len(data) && !isEndOfLink(data[linkEnd]) { -+ linkEnd++ -+ } -+ -+ // Skip punctuation at the end of the link -+ if (data[linkEnd-1] == '.' || data[linkEnd-1] == ',') && data[linkEnd-2] != '\\' { -+ linkEnd-- -+ } -+ -+ // But don't skip semicolon if it's a part of escaped entity: -+ if data[linkEnd-1] == ';' && data[linkEnd-2] != '\\' && !linkEndsWithEntity(data, linkEnd) { -+ linkEnd-- -+ } -+ -+ // See if the link finishes with a punctuation sign that can be closed. -+ var copen byte -+ switch data[linkEnd-1] { -+ case '"': -+ copen = '"' -+ case '\'': -+ copen = '\'' -+ case ')': -+ copen = '(' -+ case ']': -+ copen = '[' -+ case '}': -+ copen = '{' -+ default: -+ copen = 0 -+ } -+ -+ if copen != 0 { -+ bufEnd := offset - rewind + linkEnd - 2 -+ -+ openDelim := 1 -+ -+ /* Try to close the final punctuation sign in this same line; -+ * if we managed to close it outside of the URL, that means that it's -+ * not part of the URL. If it closes inside the URL, that means it -+ * is part of the URL. -+ * -+ * Examples: -+ * -+ * foo http://www.pokemon.com/Pikachu_(Electric) bar -+ * => http://www.pokemon.com/Pikachu_(Electric) -+ * -+ * foo (http://www.pokemon.com/Pikachu_(Electric)) bar -+ * => http://www.pokemon.com/Pikachu_(Electric) -+ * -+ * foo http://www.pokemon.com/Pikachu_(Electric)) bar -+ * => http://www.pokemon.com/Pikachu_(Electric)) -+ * -+ * (foo http://www.pokemon.com/Pikachu_(Electric)) bar -+ * => foo http://www.pokemon.com/Pikachu_(Electric) -+ */ -+ -+ for bufEnd >= 0 && origData[bufEnd] != '\n' && openDelim != 0 { -+ if origData[bufEnd] == data[linkEnd-1] { -+ openDelim++ -+ } -+ -+ if origData[bufEnd] == copen { -+ openDelim-- -+ } -+ -+ bufEnd-- -+ } -+ -+ if openDelim == 0 { -+ linkEnd-- -+ } -+ } -+ -+ // we were triggered on the ':', so we need to rewind the output a bit -+ if out.Len() >= rewind { -+ out.Truncate(len(out.Bytes()) - rewind) -+ } -+ -+ var uLink bytes.Buffer -+ unescapeText(&uLink, data[:linkEnd]) -+ -+ if uLink.Len() > 0 { -+ p.r.AutoLink(out, uLink.Bytes(), LINK_TYPE_NORMAL) -+ } -+ -+ return linkEnd - rewind -+} -+ -+func isEndOfLink(char byte) bool { -+ return isspace(char) || char == '<' -+} -+ -+var validUris = [][]byte{[]byte("http://"), []byte("https://"), []byte("ftp://"), []byte("mailto://")} -+var validPaths = [][]byte{[]byte("/"), []byte("./"), []byte("../")} -+ -+func isSafeLink(link []byte) bool { -+ for _, path := range validPaths { -+ if len(link) >= len(path) && bytes.Equal(link[:len(path)], path) { -+ if len(link) == len(path) { -+ return true -+ } else if isalnum(link[len(path)]) { -+ return true -+ } -+ } -+ } -+ -+ for _, prefix := range validUris { -+ // TODO: handle unicode here -+ // case-insensitive prefix test -+ if len(link) > len(prefix) && bytes.Equal(bytes.ToLower(link[:len(prefix)]), prefix) && isalnum(link[len(prefix)]) { -+ return true -+ } -+ } -+ -+ return false -+} -+ -+// return the length of the given tag, or 0 is it's not valid -+func tagLength(data []byte, autolink *int) int { -+ var i, j int -+ -+ // a valid tag can't be shorter than 3 chars -+ if len(data) < 3 { -+ return 0 -+ } -+ -+ // begins with a '<' optionally followed by '/', followed by letter or number -+ if data[0] != '<' { -+ return 0 -+ } -+ if data[1] == '/' { -+ i = 2 -+ } else { -+ i = 1 -+ } -+ -+ if !isalnum(data[i]) { -+ return 0 -+ } -+ -+ // scheme test -+ *autolink = LINK_TYPE_NOT_AUTOLINK -+ -+ // try to find the beginning of an URI -+ for i < len(data) && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-') { -+ i++ -+ } -+ -+ if i > 1 && i < len(data) && data[i] == '@' { -+ if j = isMailtoAutoLink(data[i:]); j != 0 { -+ *autolink = LINK_TYPE_EMAIL -+ return i + j -+ } -+ } -+ -+ if i > 2 && i < len(data) && data[i] == ':' { -+ *autolink = LINK_TYPE_NORMAL -+ i++ -+ } -+ -+ // complete autolink test: no whitespace or ' or " -+ switch { -+ case i >= len(data): -+ *autolink = LINK_TYPE_NOT_AUTOLINK -+ case *autolink != 0: -+ j = i -+ -+ for i < len(data) { -+ if data[i] == '\\' { -+ i += 2 -+ } else if data[i] == '>' || data[i] == '\'' || data[i] == '"' || isspace(data[i]) { -+ break -+ } else { -+ i++ -+ } -+ -+ } -+ -+ if i >= len(data) { -+ return 0 -+ } -+ if i > j && data[i] == '>' { -+ return i + 1 -+ } -+ -+ // one of the forbidden chars has been found -+ *autolink = LINK_TYPE_NOT_AUTOLINK -+ } -+ -+ // look for something looking like a tag end -+ for i < len(data) && data[i] != '>' { -+ i++ -+ } -+ if i >= len(data) { -+ return 0 -+ } -+ return i + 1 -+} -+ -+// look for the address part of a mail autolink and '>' -+// this is less strict than the original markdown e-mail address matching -+func isMailtoAutoLink(data []byte) int { -+ nb := 0 -+ -+ // address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' -+ for i := 0; i < len(data); i++ { -+ if isalnum(data[i]) { -+ continue -+ } -+ -+ switch data[i] { -+ case '@': -+ nb++ -+ -+ case '-', '.', '_': -+ break -+ -+ case '>': -+ if nb == 1 { -+ return i + 1 -+ } else { -+ return 0 -+ } -+ default: -+ return 0 -+ } -+ } -+ -+ return 0 -+} -+ -+// look for the next emph char, skipping other constructs -+func helperFindEmphChar(data []byte, c byte) int { -+ i := 1 -+ -+ for i < len(data) { -+ for i < len(data) && data[i] != c && data[i] != '`' && data[i] != '[' { -+ i++ -+ } -+ if i >= len(data) { -+ return 0 -+ } -+ if data[i] == c { -+ return i -+ } -+ -+ // do not count escaped chars -+ if i != 0 && data[i-1] == '\\' { -+ i++ -+ continue -+ } -+ -+ if data[i] == '`' { -+ // skip a code span -+ tmpI := 0 -+ i++ -+ for i < len(data) && data[i] != '`' { -+ if tmpI == 0 && data[i] == c { -+ tmpI = i -+ } -+ i++ -+ } -+ if i >= len(data) { -+ return tmpI -+ } -+ i++ -+ } else if data[i] == '[' { -+ // skip a link -+ tmpI := 0 -+ i++ -+ for i < len(data) && data[i] != ']' { -+ if tmpI == 0 && data[i] == c { -+ tmpI = i -+ } -+ i++ -+ } -+ i++ -+ for i < len(data) && (data[i] == ' ' || data[i] == '\n') { -+ i++ -+ } -+ if i >= len(data) { -+ return tmpI -+ } -+ if data[i] != '[' && data[i] != '(' { // not a link -+ if tmpI > 0 { -+ return tmpI -+ } else { -+ continue -+ } -+ } -+ cc := data[i] -+ i++ -+ for i < len(data) && data[i] != cc { -+ if tmpI == 0 && data[i] == c { -+ return i -+ } -+ i++ -+ } -+ if i >= len(data) { -+ return tmpI -+ } -+ i++ -+ } -+ } -+ return 0 -+} -+ -+func helperEmphasis(p *parser, out *bytes.Buffer, data []byte, c byte) int { -+ i := 0 -+ -+ // skip one symbol if coming from emph3 -+ if len(data) > 1 && data[0] == c && data[1] == c { -+ i = 1 -+ } -+ -+ for i < len(data) { -+ length := helperFindEmphChar(data[i:], c) -+ if length == 0 { -+ return 0 -+ } -+ i += length -+ if i >= len(data) { -+ return 0 -+ } -+ -+ if i+1 < len(data) && data[i+1] == c { -+ i++ -+ continue -+ } -+ -+ if data[i] == c && !isspace(data[i-1]) { -+ -+ if p.flags&EXTENSION_NO_INTRA_EMPHASIS != 0 { -+ if !(i+1 == len(data) || isspace(data[i+1]) || ispunct(data[i+1])) { -+ continue -+ } -+ } -+ -+ var work bytes.Buffer -+ p.inline(&work, data[:i]) -+ p.r.Emphasis(out, work.Bytes()) -+ return i + 1 -+ } -+ } -+ -+ return 0 -+} -+ -+func helperDoubleEmphasis(p *parser, out *bytes.Buffer, data []byte, c byte) int { -+ i := 0 -+ -+ for i < len(data) { -+ length := helperFindEmphChar(data[i:], c) -+ if length == 0 { -+ return 0 -+ } -+ i += length -+ -+ if i+1 < len(data) && data[i] == c && data[i+1] == c && i > 0 && !isspace(data[i-1]) { -+ var work bytes.Buffer -+ p.inline(&work, data[:i]) -+ -+ if work.Len() > 0 { -+ // pick the right renderer -+ if c == '~' { -+ p.r.StrikeThrough(out, work.Bytes()) -+ } else { -+ p.r.DoubleEmphasis(out, work.Bytes()) -+ } -+ } -+ return i + 2 -+ } -+ i++ -+ } -+ return 0 -+} -+ -+func helperTripleEmphasis(p *parser, out *bytes.Buffer, data []byte, offset int, c byte) int { -+ i := 0 -+ origData := data -+ data = data[offset:] -+ -+ for i < len(data) { -+ length := helperFindEmphChar(data[i:], c) -+ if length == 0 { -+ return 0 -+ } -+ i += length -+ -+ // skip whitespace preceded symbols -+ if data[i] != c || isspace(data[i-1]) { -+ continue -+ } -+ -+ switch { -+ case i+2 < len(data) && data[i+1] == c && data[i+2] == c: -+ // triple symbol found -+ var work bytes.Buffer -+ -+ p.inline(&work, data[:i]) -+ if work.Len() > 0 { -+ p.r.TripleEmphasis(out, work.Bytes()) -+ } -+ return i + 3 -+ case (i+1 < len(data) && data[i+1] == c): -+ // double symbol found, hand over to emph1 -+ length = helperEmphasis(p, out, origData[offset-2:], c) -+ if length == 0 { -+ return 0 -+ } else { -+ return length - 2 -+ } -+ default: -+ // single symbol found, hand over to emph2 -+ length = helperDoubleEmphasis(p, out, origData[offset-1:], c) -+ if length == 0 { -+ return 0 -+ } else { -+ return length - 1 -+ } -+ } -+ } -+ return 0 -+} -diff --git a/vendor/src/github.com/russross/blackfriday/inline_test.go b/vendor/src/github.com/russross/blackfriday/inline_test.go -new file mode 100644 -index 0000000..4e67d5c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/inline_test.go -@@ -0,0 +1,958 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// Unit tests for inline parsing -+// -+ -+package blackfriday -+ -+import ( -+ "regexp" -+ "testing" -+ -+ "strings" -+) -+ -+func runMarkdownInline(input string, extensions, htmlFlags int, params HtmlRendererParameters) string { -+ extensions |= EXTENSION_AUTOLINK -+ extensions |= EXTENSION_STRIKETHROUGH -+ -+ htmlFlags |= HTML_USE_XHTML -+ -+ renderer := HtmlRendererWithParameters(htmlFlags, "", "", params) -+ -+ return string(Markdown([]byte(input), renderer, extensions)) -+} -+ -+func doTestsInline(t *testing.T, tests []string) { -+ doTestsInlineParam(t, tests, 0, 0, HtmlRendererParameters{}) -+} -+ -+func doLinkTestsInline(t *testing.T, tests []string) { -+ doTestsInline(t, tests) -+ -+ prefix := "http://localhost" -+ params := HtmlRendererParameters{AbsolutePrefix: prefix} -+ transformTests := transformLinks(tests, prefix) -+ doTestsInlineParam(t, transformTests, 0, 0, params) -+ doTestsInlineParam(t, transformTests, 0, commonHtmlFlags, params) -+} -+ -+func doSafeTestsInline(t *testing.T, tests []string) { -+ doTestsInlineParam(t, tests, 0, HTML_SAFELINK, HtmlRendererParameters{}) -+ -+ // All the links in this test should not have the prefix appended, so -+ // just rerun it with different parameters and the same expectations. -+ prefix := "http://localhost" -+ params := HtmlRendererParameters{AbsolutePrefix: prefix} -+ transformTests := transformLinks(tests, prefix) -+ doTestsInlineParam(t, transformTests, 0, HTML_SAFELINK, params) -+} -+ -+func doTestsInlineParam(t *testing.T, tests []string, extensions, htmlFlags int, -+ params HtmlRendererParameters) { -+ // catch and report panics -+ var candidate string -+ /* -+ defer func() { -+ if err := recover(); err != nil { -+ t.Errorf("\npanic while processing [%#v] (%v)\n", candidate, err) -+ } -+ }() -+ */ -+ -+ for i := 0; i+1 < len(tests); i += 2 { -+ input := tests[i] -+ candidate = input -+ expected := tests[i+1] -+ -+ actual := runMarkdownInline(candidate, extensions, htmlFlags, params) -+ if actual != expected { -+ t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", -+ candidate, expected, actual) -+ } -+ -+ // now test every substring to stress test bounds checking -+ if !testing.Short() { -+ for start := 0; start < len(input); start++ { -+ for end := start + 1; end <= len(input); end++ { -+ candidate = input[start:end] -+ _ = runMarkdownInline(candidate, extensions, htmlFlags, params) -+ } -+ } -+ } -+ } -+} -+ -+func transformLinks(tests []string, prefix string) []string { -+ newTests := make([]string, len(tests)) -+ anchorRe := regexp.MustCompile(`<a href="/(.*?)"`) -+ imgRe := regexp.MustCompile(`<img src="/(.*?)"`) -+ for i, test := range tests { -+ if i%2 == 1 { -+ test = anchorRe.ReplaceAllString(test, `<a href="`+prefix+`/$1"`) -+ test = imgRe.ReplaceAllString(test, `<img src="`+prefix+`/$1"`) -+ } -+ newTests[i] = test -+ } -+ return newTests -+} -+ -+func TestEmphasis(t *testing.T) { -+ var tests = []string{ -+ "nothing inline\n", -+ "<p>nothing inline</p>\n", -+ -+ "simple *inline* test\n", -+ "<p>simple <em>inline</em> test</p>\n", -+ -+ "*at the* beginning\n", -+ "<p><em>at the</em> beginning</p>\n", -+ -+ "at the *end*\n", -+ "<p>at the <em>end</em></p>\n", -+ -+ "*try two* in *one line*\n", -+ "<p><em>try two</em> in <em>one line</em></p>\n", -+ -+ "over *two\nlines* test\n", -+ "<p>over <em>two\nlines</em> test</p>\n", -+ -+ "odd *number of* markers* here\n", -+ "<p>odd <em>number of</em> markers* here</p>\n", -+ -+ "odd *number\nof* markers* here\n", -+ "<p>odd <em>number\nof</em> markers* here</p>\n", -+ -+ "simple _inline_ test\n", -+ "<p>simple <em>inline</em> test</p>\n", -+ -+ "_at the_ beginning\n", -+ "<p><em>at the</em> beginning</p>\n", -+ -+ "at the _end_\n", -+ "<p>at the <em>end</em></p>\n", -+ -+ "_try two_ in _one line_\n", -+ "<p><em>try two</em> in <em>one line</em></p>\n", -+ -+ "over _two\nlines_ test\n", -+ "<p>over <em>two\nlines</em> test</p>\n", -+ -+ "odd _number of_ markers_ here\n", -+ "<p>odd <em>number of</em> markers_ here</p>\n", -+ -+ "odd _number\nof_ markers_ here\n", -+ "<p>odd <em>number\nof</em> markers_ here</p>\n", -+ -+ "mix of *markers_\n", -+ "<p>mix of *markers_</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestStrong(t *testing.T) { -+ var tests = []string{ -+ "nothing inline\n", -+ "<p>nothing inline</p>\n", -+ -+ "simple **inline** test\n", -+ "<p>simple <strong>inline</strong> test</p>\n", -+ -+ "**at the** beginning\n", -+ "<p><strong>at the</strong> beginning</p>\n", -+ -+ "at the **end**\n", -+ "<p>at the <strong>end</strong></p>\n", -+ -+ "**try two** in **one line**\n", -+ "<p><strong>try two</strong> in <strong>one line</strong></p>\n", -+ -+ "over **two\nlines** test\n", -+ "<p>over <strong>two\nlines</strong> test</p>\n", -+ -+ "odd **number of** markers** here\n", -+ "<p>odd <strong>number of</strong> markers** here</p>\n", -+ -+ "odd **number\nof** markers** here\n", -+ "<p>odd <strong>number\nof</strong> markers** here</p>\n", -+ -+ "simple __inline__ test\n", -+ "<p>simple <strong>inline</strong> test</p>\n", -+ -+ "__at the__ beginning\n", -+ "<p><strong>at the</strong> beginning</p>\n", -+ -+ "at the __end__\n", -+ "<p>at the <strong>end</strong></p>\n", -+ -+ "__try two__ in __one line__\n", -+ "<p><strong>try two</strong> in <strong>one line</strong></p>\n", -+ -+ "over __two\nlines__ test\n", -+ "<p>over <strong>two\nlines</strong> test</p>\n", -+ -+ "odd __number of__ markers__ here\n", -+ "<p>odd <strong>number of</strong> markers__ here</p>\n", -+ -+ "odd __number\nof__ markers__ here\n", -+ "<p>odd <strong>number\nof</strong> markers__ here</p>\n", -+ -+ "mix of **markers__\n", -+ "<p>mix of **markers__</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestEmphasisMix(t *testing.T) { -+ var tests = []string{ -+ "***triple emphasis***\n", -+ "<p><strong><em>triple emphasis</em></strong></p>\n", -+ -+ "***triple\nemphasis***\n", -+ "<p><strong><em>triple\nemphasis</em></strong></p>\n", -+ -+ "___triple emphasis___\n", -+ "<p><strong><em>triple emphasis</em></strong></p>\n", -+ -+ "***triple emphasis___\n", -+ "<p>***triple emphasis___</p>\n", -+ -+ "*__triple emphasis__*\n", -+ "<p><em><strong>triple emphasis</strong></em></p>\n", -+ -+ "__*triple emphasis*__\n", -+ "<p><strong><em>triple emphasis</em></strong></p>\n", -+ -+ "**improper *nesting** is* bad\n", -+ "<p><strong>improper *nesting</strong> is* bad</p>\n", -+ -+ "*improper **nesting* is** bad\n", -+ "<p><em>improper **nesting</em> is** bad</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestEmphasisLink(t *testing.T) { -+ var tests = []string{ -+ "[first](before) *text[second] (inside)text* [third](after)\n", -+ "<p><a href=\"before\">first</a> <em>text<a href=\"inside\">second</a>text</em> <a href=\"after\">third</a></p>\n", -+ -+ "*incomplete [link] definition*\n", -+ "<p><em>incomplete [link] definition</em></p>\n", -+ -+ "*it's [emphasis*] (not link)\n", -+ "<p><em>it's [emphasis</em>] (not link)</p>\n", -+ -+ "*it's [emphasis*] and *[asterisk]\n", -+ "<p><em>it's [emphasis</em>] and *[asterisk]</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestStrikeThrough(t *testing.T) { -+ var tests = []string{ -+ "nothing inline\n", -+ "<p>nothing inline</p>\n", -+ -+ "simple ~~inline~~ test\n", -+ "<p>simple <del>inline</del> test</p>\n", -+ -+ "~~at the~~ beginning\n", -+ "<p><del>at the</del> beginning</p>\n", -+ -+ "at the ~~end~~\n", -+ "<p>at the <del>end</del></p>\n", -+ -+ "~~try two~~ in ~~one line~~\n", -+ "<p><del>try two</del> in <del>one line</del></p>\n", -+ -+ "over ~~two\nlines~~ test\n", -+ "<p>over <del>two\nlines</del> test</p>\n", -+ -+ "odd ~~number of~~ markers~~ here\n", -+ "<p>odd <del>number of</del> markers~~ here</p>\n", -+ -+ "odd ~~number\nof~~ markers~~ here\n", -+ "<p>odd <del>number\nof</del> markers~~ here</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestCodeSpan(t *testing.T) { -+ var tests = []string{ -+ "`source code`\n", -+ "<p><code>source code</code></p>\n", -+ -+ "` source code with spaces `\n", -+ "<p><code>source code with spaces</code></p>\n", -+ -+ "` source code with spaces `not here\n", -+ "<p><code>source code with spaces</code>not here</p>\n", -+ -+ "a `single marker\n", -+ "<p>a `single marker</p>\n", -+ -+ "a single multi-tick marker with ``` no text\n", -+ "<p>a single multi-tick marker with ``` no text</p>\n", -+ -+ "markers with ` ` a space\n", -+ "<p>markers with a space</p>\n", -+ -+ "`source code` and a `stray\n", -+ "<p><code>source code</code> and a `stray</p>\n", -+ -+ "`source *with* _awkward characters_ in it`\n", -+ "<p><code>source *with* _awkward characters_ in it</code></p>\n", -+ -+ "`split over\ntwo lines`\n", -+ "<p><code>split over\ntwo lines</code></p>\n", -+ -+ "```multiple ticks``` for the marker\n", -+ "<p><code>multiple ticks</code> for the marker</p>\n", -+ -+ "```multiple ticks `with` ticks inside```\n", -+ "<p><code>multiple ticks `with` ticks inside</code></p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestLineBreak(t *testing.T) { -+ var tests = []string{ -+ "this line \nhas a break\n", -+ "<p>this line<br />\nhas a break</p>\n", -+ -+ "this line \ndoes not\n", -+ "<p>this line\ndoes not</p>\n", -+ -+ "this line\\\ndoes not\n", -+ "<p>this line\\\ndoes not</p>\n", -+ -+ "this line\\ \ndoes not\n", -+ "<p>this line\\\ndoes not</p>\n", -+ -+ "this has an \nextra space\n", -+ "<p>this has an<br />\nextra space</p>\n", -+ } -+ doTestsInline(t, tests) -+ -+ tests = []string{ -+ "this line \nhas a break\n", -+ "<p>this line<br />\nhas a break</p>\n", -+ -+ "this line \ndoes not\n", -+ "<p>this line\ndoes not</p>\n", -+ -+ "this line\\\nhas a break\n", -+ "<p>this line<br />\nhas a break</p>\n", -+ -+ "this line\\ \ndoes not\n", -+ "<p>this line\\\ndoes not</p>\n", -+ -+ "this has an \nextra space\n", -+ "<p>this has an<br />\nextra space</p>\n", -+ } -+ doTestsInlineParam(t, tests, EXTENSION_BACKSLASH_LINE_BREAK, 0, HtmlRendererParameters{}) -+} -+ -+func TestInlineLink(t *testing.T) { -+ var tests = []string{ -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ -+ "[foo with a title](/bar/ \"title\")\n", -+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n", -+ -+ "[foo with a title](/bar/\t\"title\")\n", -+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n", -+ -+ "[foo with a title](/bar/ \"title\" )\n", -+ "<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n", -+ -+ "[foo with a title](/bar/ title with no quotes)\n", -+ "<p><a href=\"/bar/ title with no quotes\">foo with a title</a></p>\n", -+ -+ "[foo]()\n", -+ "<p>[foo]()</p>\n", -+ -+ "\n", -+ "<p><img src=\"/bar/\" alt=\"foo\" />\n</p>\n", -+ -+ "\n", -+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", -+ -+ "\n", -+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", -+ -+ "\n", -+ "<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n", -+ -+ "\n", -+ "<p><img src=\"/bar/ title with no quotes\" alt=\"foo with a title\" />\n</p>\n", -+ -+ "\n", -+ "<p><img src=\"img.jpg\" alt=\"\" />\n</p>\n", -+ -+ "[link](url)\n", -+ "<p><a href=\"url\">link</a></p>\n", -+ -+ "![foo]()\n", -+ "<p>![foo]()</p>\n", -+ -+ "[a link]\t(/with_a_tab/)\n", -+ "<p><a href=\"/with_a_tab/\">a link</a></p>\n", -+ -+ "[a link] (/with_spaces/)\n", -+ "<p><a href=\"/with_spaces/\">a link</a></p>\n", -+ -+ "[text (with) [[nested] (brackets)]](/url/)\n", -+ "<p><a href=\"/url/\">text (with) [[nested] (brackets)]</a></p>\n", -+ -+ "[text (with) [broken nested] (brackets)]](/url/)\n", -+ "<p>[text (with) <a href=\"brackets\">broken nested</a>]](/url/)</p>\n", -+ -+ "[text\nwith a newline](/link/)\n", -+ "<p><a href=\"/link/\">text\nwith a newline</a></p>\n", -+ -+ "[text in brackets] [followed](/by a link/)\n", -+ "<p>[text in brackets] <a href=\"/by a link/\">followed</a></p>\n", -+ -+ "[link with\\] a closing bracket](/url/)\n", -+ "<p><a href=\"/url/\">link with] a closing bracket</a></p>\n", -+ -+ "[link with\\[ an opening bracket](/url/)\n", -+ "<p><a href=\"/url/\">link with[ an opening bracket</a></p>\n", -+ -+ "[link with\\) a closing paren](/url/)\n", -+ "<p><a href=\"/url/\">link with) a closing paren</a></p>\n", -+ -+ "[link with\\( an opening paren](/url/)\n", -+ "<p><a href=\"/url/\">link with( an opening paren</a></p>\n", -+ -+ "[link]( with whitespace)\n", -+ "<p><a href=\"with whitespace\">link</a></p>\n", -+ -+ "[link]( with whitespace )\n", -+ "<p><a href=\"with whitespace\">link</a></p>\n", -+ -+ "[](with image)\n", -+ "<p><a href=\"with image\"><img src=\"someimage\" alt=\"image\" />\n</a></p>\n", -+ -+ "[link](url \"one quote)\n", -+ "<p><a href=\"url "one quote\">link</a></p>\n", -+ -+ "[link](url 'one quote)\n", -+ "<p><a href=\"url 'one quote\">link</a></p>\n", -+ -+ "[link](<url>)\n", -+ "<p><a href=\"url\">link</a></p>\n", -+ -+ "[link & ampersand](/url/)\n", -+ "<p><a href=\"/url/\">link & ampersand</a></p>\n", -+ -+ "[link & ampersand](/url/)\n", -+ "<p><a href=\"/url/\">link & ampersand</a></p>\n", -+ -+ "[link](/url/&query)\n", -+ "<p><a href=\"/url/&query\">link</a></p>\n", -+ -+ "[[t]](/t)\n", -+ "<p><a href=\"/t\">[t]</a></p>\n", -+ -+ "[link](</>)\n", -+ "<p><a href=\"/\">link</a></p>\n", -+ -+ "[link](<./>)\n", -+ "<p><a href=\"./\">link</a></p>\n", -+ -+ "[link](<../>)\n", -+ "<p><a href=\"../\">link</a></p>\n", -+ } -+ doLinkTestsInline(t, tests) -+ -+} -+ -+func TestRelAttrLink(t *testing.T) { -+ var nofollowTests = []string{ -+ "[foo](http://bar.com/foo/)\n", -+ "<p><a href=\"http://bar.com/foo/\" rel=\"nofollow\">foo</a></p>\n", -+ -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ -+ "[foo](/)\n", -+ "<p><a href=\"/\">foo</a></p>\n", -+ -+ "[foo](./)\n", -+ "<p><a href=\"./\">foo</a></p>\n", -+ -+ "[foo](../)\n", -+ "<p><a href=\"../\">foo</a></p>\n", -+ -+ "[foo](../bar)\n", -+ "<p><a href=\"../bar\">foo</a></p>\n", -+ } -+ doTestsInlineParam(t, nofollowTests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS, -+ HtmlRendererParameters{}) -+ -+ var noreferrerTests = []string{ -+ "[foo](http://bar.com/foo/)\n", -+ "<p><a href=\"http://bar.com/foo/\" rel=\"noreferrer\">foo</a></p>\n", -+ -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ } -+ doTestsInlineParam(t, noreferrerTests, 0, HTML_SAFELINK|HTML_NOREFERRER_LINKS, -+ HtmlRendererParameters{}) -+ -+ var nofollownoreferrerTests = []string{ -+ "[foo](http://bar.com/foo/)\n", -+ "<p><a href=\"http://bar.com/foo/\" rel=\"nofollow noreferrer\">foo</a></p>\n", -+ -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ } -+ doTestsInlineParam(t, nofollownoreferrerTests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS|HTML_NOREFERRER_LINKS, -+ HtmlRendererParameters{}) -+} -+ -+func TestHrefTargetBlank(t *testing.T) { -+ var tests = []string{ -+ // internal link -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ -+ "[foo](/)\n", -+ "<p><a href=\"/\">foo</a></p>\n", -+ -+ "[foo](./)\n", -+ "<p><a href=\"./\">foo</a></p>\n", -+ -+ "[foo](./bar)\n", -+ "<p><a href=\"./bar\">foo</a></p>\n", -+ -+ "[foo](../)\n", -+ "<p><a href=\"../\">foo</a></p>\n", -+ -+ "[foo](../bar)\n", -+ "<p><a href=\"../bar\">foo</a></p>\n", -+ -+ "[foo](http://example.com)\n", -+ "<p><a href=\"http://example.com\" target=\"_blank\">foo</a></p>\n", -+ } -+ doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_HREF_TARGET_BLANK, HtmlRendererParameters{}) -+} -+ -+func TestSafeInlineLink(t *testing.T) { -+ var tests = []string{ -+ "[foo](/bar/)\n", -+ "<p><a href=\"/bar/\">foo</a></p>\n", -+ -+ "[foo](/)\n", -+ "<p><a href=\"/\">foo</a></p>\n", -+ -+ "[foo](./)\n", -+ "<p><a href=\"./\">foo</a></p>\n", -+ -+ "[foo](../)\n", -+ "<p><a href=\"../\">foo</a></p>\n", -+ -+ "[foo](http://bar/)\n", -+ "<p><a href=\"http://bar/\">foo</a></p>\n", -+ -+ "[foo](https://bar/)\n", -+ "<p><a href=\"https://bar/\">foo</a></p>\n", -+ -+ "[foo](ftp://bar/)\n", -+ "<p><a href=\"ftp://bar/\">foo</a></p>\n", -+ -+ "[foo](mailto://bar/)\n", -+ "<p><a href=\"mailto://bar/\">foo</a></p>\n", -+ -+ // Not considered safe -+ "[foo](baz://bar/)\n", -+ "<p><tt>foo</tt></p>\n", -+ } -+ doSafeTestsInline(t, tests) -+} -+ -+func TestReferenceLink(t *testing.T) { -+ var tests = []string{ -+ "[link][ref]\n", -+ "<p>[link][ref]</p>\n", -+ -+ "[link][ref]\n [ref]: /url/ \"title\"\n", -+ "<p><a href=\"/url/\" title=\"title\">link</a></p>\n", -+ -+ "[link][ref]\n [ref]: /url/\n", -+ "<p><a href=\"/url/\">link</a></p>\n", -+ -+ " [ref]: /url/\n", -+ "", -+ -+ " [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n", -+ "", -+ -+ " [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n [4spaces]: /url/\n", -+ "<pre><code>[4spaces]: /url/\n</code></pre>\n", -+ -+ "[hmm](ref2)\n [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n", -+ "<p><a href=\"ref2\">hmm</a></p>\n", -+ -+ "[ref]\n", -+ "<p>[ref]</p>\n", -+ -+ "[ref]\n [ref]: /url/ \"title\"\n", -+ "<p><a href=\"/url/\" title=\"title\">ref</a></p>\n", -+ -+ "[ref]\n [ref]: ../url/ \"title\"\n", -+ "<p><a href=\"../url/\" title=\"title\">ref</a></p>\n", -+ } -+ doLinkTestsInline(t, tests) -+} -+ -+func TestTags(t *testing.T) { -+ var tests = []string{ -+ "a <span>tag</span>\n", -+ "<p>a <span>tag</span></p>\n", -+ -+ "<span>tag</span>\n", -+ "<p><span>tag</span></p>\n", -+ -+ "<span>mismatch</spandex>\n", -+ "<p><span>mismatch</spandex></p>\n", -+ -+ "a <singleton /> tag\n", -+ "<p>a <singleton /> tag</p>\n", -+ } -+ doTestsInline(t, tests) -+} -+ -+func TestAutoLink(t *testing.T) { -+ var tests = []string{ -+ "http://foo.com/\n", -+ "<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "1 http://foo.com/\n", -+ "<p>1 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "1http://foo.com/\n", -+ "<p>1<a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "1.http://foo.com/\n", -+ "<p>1.<a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "1. http://foo.com/\n", -+ "<ol>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ol>\n", -+ -+ "-http://foo.com/\n", -+ "<p>-<a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "- http://foo.com/\n", -+ "<ul>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ul>\n", -+ -+ "_http://foo.com/\n", -+ "<p>_<a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "令狐http://foo.com/\n", -+ "<p>令狐<a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "令狐 http://foo.com/\n", -+ "<p>令狐 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "ahttp://foo.com/\n", -+ "<p>ahttp://foo.com/</p>\n", -+ -+ ">http://foo.com/\n", -+ "<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n", -+ -+ "> http://foo.com/\n", -+ "<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n", -+ -+ "go to <http://foo.com/>\n", -+ "<p>go to <a href=\"http://foo.com/\">http://foo.com/</a></p>\n", -+ -+ "a secure <https://link.org>\n", -+ "<p>a secure <a href=\"https://link.org\">https://link.org</a></p>\n", -+ -+ "an email <mailto:some@one.com>\n", -+ "<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n", -+ -+ "an email <mailto://some@one.com>\n", -+ "<p>an email <a href=\"mailto://some@one.com\">some@one.com</a></p>\n", -+ -+ "an email <some@one.com>\n", -+ "<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n", -+ -+ "an ftp <ftp://old.com>\n", -+ "<p>an ftp <a href=\"ftp://old.com\">ftp://old.com</a></p>\n", -+ -+ "an ftp <ftp:old.com>\n", -+ "<p>an ftp <a href=\"ftp:old.com\">ftp:old.com</a></p>\n", -+ -+ "a link with <http://new.com?query=foo&bar>\n", -+ "<p>a link with <a href=\"http://new.com?query=foo&bar\">" + -+ "http://new.com?query=foo&bar</a></p>\n", -+ -+ "quotes mean a tag <http://new.com?query=\"foo\"&bar>\n", -+ "<p>quotes mean a tag <http://new.com?query=\"foo\"&bar></p>\n", -+ -+ "quotes mean a tag <http://new.com?query='foo'&bar>\n", -+ "<p>quotes mean a tag <http://new.com?query='foo'&bar></p>\n", -+ -+ "unless escaped <http://new.com?query=\\\"foo\\\"&bar>\n", -+ "<p>unless escaped <a href=\"http://new.com?query="foo"&bar\">" + -+ "http://new.com?query="foo"&bar</a></p>\n", -+ -+ "even a > can be escaped <http://new.com?q=\\>&etc>\n", -+ "<p>even a > can be escaped <a href=\"http://new.com?q=>&etc\">" + -+ "http://new.com?q=>&etc</a></p>\n", -+ -+ "<a href=\"http://fancy.com\">http://fancy.com</a>\n", -+ "<p><a href=\"http://fancy.com\">http://fancy.com</a></p>\n", -+ -+ "<a href=\"http://fancy.com\">This is a link</a>\n", -+ "<p><a href=\"http://fancy.com\">This is a link</a></p>\n", -+ -+ "<a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a>\n", -+ "<p><a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a></p>\n", -+ -+ "(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (\n", -+ "<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (</p>\n", -+ -+ "(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).\n", -+ "<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).</p>\n", -+ -+ "http://www.foo.com<br />\n", -+ "<p><a href=\"http://www.foo.com\">http://www.foo.com</a><br /></p>\n", -+ -+ "http://foo.com/viewtopic.php?f=18&t=297", -+ "<p><a href=\"http://foo.com/viewtopic.php?f=18&t=297\">http://foo.com/viewtopic.php?f=18&t=297</a></p>\n", -+ -+ "http://foo.com/viewtopic.php?param="18"zz", -+ "<p><a href=\"http://foo.com/viewtopic.php?param="18"zz\">http://foo.com/viewtopic.php?param="18"zz</a></p>\n", -+ -+ "http://foo.com/viewtopic.php?param="18"", -+ "<p><a href=\"http://foo.com/viewtopic.php?param="18"\">http://foo.com/viewtopic.php?param="18"</a></p>\n", -+ } -+ doLinkTestsInline(t, tests) -+} -+ -+var footnoteTests = []string{ -+ "testing footnotes.[^a]\n\n[^a]: This is the note\n", -+ `<p>testing footnotes.<sup class="footnote-ref" id="fnref:a"><a rel="footnote" href="#fn:a">1</a></sup></p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:a">This is the note -+</li> -+</ol> -+</div> -+`, -+ -+ `testing long[^b] notes. -+ -+[^b]: Paragraph 1 -+ -+ Paragraph 2 -+ -+ ` + "```\n\tsome code\n\t```" + ` -+ -+ Paragraph 3 -+ -+No longer in the footnote -+`, -+ `<p>testing long<sup class="footnote-ref" id="fnref:b"><a rel="footnote" href="#fn:b">1</a></sup> notes.</p> -+ -+<p>No longer in the footnote</p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:b"><p>Paragraph 1</p> -+ -+<p>Paragraph 2</p> -+ -+<p><code> -+some code -+</code></p> -+ -+<p>Paragraph 3</p> -+</li> -+</ol> -+</div> -+`, -+ -+ `testing[^c] multiple[^d] notes. -+ -+[^c]: this is [note] c -+ -+ -+omg -+ -+[^d]: this is note d -+ -+what happens here -+ -+[note]: /link/c -+ -+`, -+ `<p>testing<sup class="footnote-ref" id="fnref:c"><a rel="footnote" href="#fn:c">1</a></sup> multiple<sup class="footnote-ref" id="fnref:d"><a rel="footnote" href="#fn:d">2</a></sup> notes.</p> -+ -+<p>omg</p> -+ -+<p>what happens here</p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:c">this is <a href="/link/c">note</a> c -+</li> -+<li id="fn:d">this is note d -+</li> -+</ol> -+</div> -+`, -+ -+ "testing inline^[this is the note] notes.\n", -+ `<p>testing inline<sup class="footnote-ref" id="fnref:this-is-the-note"><a rel="footnote" href="#fn:this-is-the-note">1</a></sup> notes.</p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:this-is-the-note">this is the note</li> -+</ol> -+</div> -+`, -+ -+ "testing multiple[^1] types^[inline note] of notes[^2]\n\n[^2]: the second deferred note\n[^1]: the first deferred note\n\n\twhich happens to be a block\n", -+ `<p>testing multiple<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup> types<sup class="footnote-ref" id="fnref:inline-note"><a rel="footnote" href="#fn:inline-note">2</a></sup> of notes<sup class="footnote-ref" id="fnref:2"><a rel="footnote" href="#fn:2">3</a></sup></p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:1"><p>the first deferred note</p> -+ -+<p>which happens to be a block</p> -+</li> -+<li id="fn:inline-note">inline note</li> -+<li id="fn:2">the second deferred note -+</li> -+</ol> -+</div> -+`, -+ -+ `This is a footnote[^1]^[and this is an inline footnote] -+ -+[^1]: the footnote text. -+ -+ may be multiple paragraphs. -+`, -+ `<p>This is a footnote<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup><sup class="footnote-ref" id="fnref:and-this-is-an-i"><a rel="footnote" href="#fn:and-this-is-an-i">2</a></sup></p> -+<div class="footnotes"> -+ -+<hr /> -+ -+<ol> -+<li id="fn:1"><p>the footnote text.</p> -+ -+<p>may be multiple paragraphs.</p> -+</li> -+<li id="fn:and-this-is-an-i">and this is an inline footnote</li> -+</ol> -+</div> -+`, -+ -+ "empty footnote[^]\n\n[^]: fn text", -+ "<p>empty footnote<sup class=\"footnote-ref\" id=\"fnref:\"><a rel=\"footnote\" href=\"#fn:\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:\">fn text\n</li>\n</ol>\n</div>\n", -+ -+ "Some text.[^note1]\n\n[^note1]: fn1", -+ "<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n</ol>\n</div>\n", -+ -+ "Some text.[^note1][^note2]\n\n[^note1]: fn1\n[^note2]: fn2\n", -+ "<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup><sup class=\"footnote-ref\" id=\"fnref:note2\"><a rel=\"footnote\" href=\"#fn:note2\">2</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n<li id=\"fn:note2\">fn2\n</li>\n</ol>\n</div>\n", -+} -+ -+func TestFootnotes(t *testing.T) { -+ doTestsInlineParam(t, footnoteTests, EXTENSION_FOOTNOTES, 0, HtmlRendererParameters{}) -+} -+ -+func TestFootnotesWithParameters(t *testing.T) { -+ tests := make([]string, len(footnoteTests)) -+ -+ prefix := "testPrefix" -+ returnText := "ret" -+ re := regexp.MustCompile(`(?ms)<li id="fn:(\S+?)">(.*?)</li>`) -+ -+ // Transform the test expectations to match the parameters we're using. -+ for i, test := range footnoteTests { -+ if i%2 == 1 { -+ test = strings.Replace(test, "fn:", "fn:"+prefix, -1) -+ test = strings.Replace(test, "fnref:", "fnref:"+prefix, -1) -+ test = re.ReplaceAllString(test, `<li id="fn:$1">$2 <a class="footnote-return" href="#fnref:$1">ret</a></li>`) -+ } -+ tests[i] = test -+ } -+ -+ params := HtmlRendererParameters{ -+ FootnoteAnchorPrefix: prefix, -+ FootnoteReturnLinkContents: returnText, -+ } -+ -+ doTestsInlineParam(t, tests, EXTENSION_FOOTNOTES, HTML_FOOTNOTE_RETURN_LINKS, params) -+} -+ -+func TestSmartDoubleQuotes(t *testing.T) { -+ var tests = []string{ -+ "this should be normal \"quoted\" text.\n", -+ "<p>this should be normal “quoted” text.</p>\n", -+ "this \" single double\n", -+ "<p>this “ single double</p>\n", -+ "two pair of \"some\" quoted \"text\".\n", -+ "<p>two pair of “some” quoted “text”.</p>\n"} -+ -+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS, HtmlRendererParameters{}) -+} -+ -+func TestSmartAngledDoubleQuotes(t *testing.T) { -+ var tests = []string{ -+ "this should be angled \"quoted\" text.\n", -+ "<p>this should be angled «quoted» text.</p>\n", -+ "this \" single double\n", -+ "<p>this « single double</p>\n", -+ "two pair of \"some\" quoted \"text\".\n", -+ "<p>two pair of «some» quoted «text».</p>\n"} -+ -+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_ANGLED_QUOTES, HtmlRendererParameters{}) -+} -+ -+func TestSmartFractions(t *testing.T) { -+ var tests = []string{ -+ "1/2, 1/4 and 3/4; 1/4th and 3/4ths\n", -+ "<p>½, ¼ and ¾; ¼th and ¾ths</p>\n", -+ "1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n", -+ "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"} -+ -+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS, HtmlRendererParameters{}) -+ -+ tests = []string{ -+ "1/2, 2/3, 81/100 and 1000000/1048576.\n", -+ "<p><sup>1</sup>⁄<sub>2</sub>, <sup>2</sup>⁄<sub>3</sub>, <sup>81</sup>⁄<sub>100</sub> and <sup>1000000</sup>⁄<sub>1048576</sub>.</p>\n", -+ "1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n", -+ "<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n"} -+ -+ doTestsInlineParam(t, tests, 0, HTML_USE_SMARTYPANTS|HTML_SMARTYPANTS_FRACTIONS, HtmlRendererParameters{}) -+} -diff --git a/vendor/src/github.com/russross/blackfriday/latex.go b/vendor/src/github.com/russross/blackfriday/latex.go -new file mode 100644 -index 0000000..8562746 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/latex.go -@@ -0,0 +1,332 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// -+// LaTeX rendering backend -+// -+// -+ -+package blackfriday -+ -+import ( -+ "bytes" -+) -+ -+// Latex is a type that implements the Renderer interface for LaTeX output. -+// -+// Do not create this directly, instead use the LatexRenderer function. -+type Latex struct { -+} -+ -+// LatexRenderer creates and configures a Latex object, which -+// satisfies the Renderer interface. -+// -+// flags is a set of LATEX_* options ORed together (currently no such options -+// are defined). -+func LatexRenderer(flags int) Renderer { -+ return &Latex{} -+} -+ -+func (options *Latex) GetFlags() int { -+ return 0 -+} -+ -+// render code chunks using verbatim, or listings if we have a language -+func (options *Latex) BlockCode(out *bytes.Buffer, text []byte, lang string) { -+ if lang == "" { -+ out.WriteString("\n\\begin{verbatim}\n") -+ } else { -+ out.WriteString("\n\\begin{lstlisting}[language=") -+ out.WriteString(lang) -+ out.WriteString("]\n") -+ } -+ out.Write(text) -+ if lang == "" { -+ out.WriteString("\n\\end{verbatim}\n") -+ } else { -+ out.WriteString("\n\\end{lstlisting}\n") -+ } -+} -+ -+func (options *Latex) TitleBlock(out *bytes.Buffer, text []byte) { -+ -+} -+ -+func (options *Latex) BlockQuote(out *bytes.Buffer, text []byte) { -+ out.WriteString("\n\\begin{quotation}\n") -+ out.Write(text) -+ out.WriteString("\n\\end{quotation}\n") -+} -+ -+func (options *Latex) BlockHtml(out *bytes.Buffer, text []byte) { -+ // a pretty lame thing to do... -+ out.WriteString("\n\\begin{verbatim}\n") -+ out.Write(text) -+ out.WriteString("\n\\end{verbatim}\n") -+} -+ -+func (options *Latex) Header(out *bytes.Buffer, text func() bool, level int, id string) { -+ marker := out.Len() -+ -+ switch level { -+ case 1: -+ out.WriteString("\n\\section{") -+ case 2: -+ out.WriteString("\n\\subsection{") -+ case 3: -+ out.WriteString("\n\\subsubsection{") -+ case 4: -+ out.WriteString("\n\\paragraph{") -+ case 5: -+ out.WriteString("\n\\subparagraph{") -+ case 6: -+ out.WriteString("\n\\textbf{") -+ } -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ out.WriteString("}\n") -+} -+ -+func (options *Latex) HRule(out *bytes.Buffer) { -+ out.WriteString("\n\\HRule\n") -+} -+ -+func (options *Latex) List(out *bytes.Buffer, text func() bool, flags int) { -+ marker := out.Len() -+ if flags&LIST_TYPE_ORDERED != 0 { -+ out.WriteString("\n\\begin{enumerate}\n") -+ } else { -+ out.WriteString("\n\\begin{itemize}\n") -+ } -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ if flags&LIST_TYPE_ORDERED != 0 { -+ out.WriteString("\n\\end{enumerate}\n") -+ } else { -+ out.WriteString("\n\\end{itemize}\n") -+ } -+} -+ -+func (options *Latex) ListItem(out *bytes.Buffer, text []byte, flags int) { -+ out.WriteString("\n\\item ") -+ out.Write(text) -+} -+ -+func (options *Latex) Paragraph(out *bytes.Buffer, text func() bool) { -+ marker := out.Len() -+ out.WriteString("\n") -+ if !text() { -+ out.Truncate(marker) -+ return -+ } -+ out.WriteString("\n") -+} -+ -+func (options *Latex) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { -+ out.WriteString("\n\\begin{tabular}{") -+ for _, elt := range columnData { -+ switch elt { -+ case TABLE_ALIGNMENT_LEFT: -+ out.WriteByte('l') -+ case TABLE_ALIGNMENT_RIGHT: -+ out.WriteByte('r') -+ default: -+ out.WriteByte('c') -+ } -+ } -+ out.WriteString("}\n") -+ out.Write(header) -+ out.WriteString(" \\\\\n\\hline\n") -+ out.Write(body) -+ out.WriteString("\n\\end{tabular}\n") -+} -+ -+func (options *Latex) TableRow(out *bytes.Buffer, text []byte) { -+ if out.Len() > 0 { -+ out.WriteString(" \\\\\n") -+ } -+ out.Write(text) -+} -+ -+func (options *Latex) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { -+ if out.Len() > 0 { -+ out.WriteString(" & ") -+ } -+ out.Write(text) -+} -+ -+func (options *Latex) TableCell(out *bytes.Buffer, text []byte, align int) { -+ if out.Len() > 0 { -+ out.WriteString(" & ") -+ } -+ out.Write(text) -+} -+ -+// TODO: this -+func (options *Latex) Footnotes(out *bytes.Buffer, text func() bool) { -+ -+} -+ -+func (options *Latex) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { -+ -+} -+ -+func (options *Latex) AutoLink(out *bytes.Buffer, link []byte, kind int) { -+ out.WriteString("\\href{") -+ if kind == LINK_TYPE_EMAIL { -+ out.WriteString("mailto:") -+ } -+ out.Write(link) -+ out.WriteString("}{") -+ out.Write(link) -+ out.WriteString("}") -+} -+ -+func (options *Latex) CodeSpan(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\texttt{") -+ escapeSpecialChars(out, text) -+ out.WriteString("}") -+} -+ -+func (options *Latex) DoubleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\textbf{") -+ out.Write(text) -+ out.WriteString("}") -+} -+ -+func (options *Latex) Emphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\textit{") -+ out.Write(text) -+ out.WriteString("}") -+} -+ -+func (options *Latex) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { -+ if bytes.HasPrefix(link, []byte("http://")) || bytes.HasPrefix(link, []byte("https://")) { -+ // treat it like a link -+ out.WriteString("\\href{") -+ out.Write(link) -+ out.WriteString("}{") -+ out.Write(alt) -+ out.WriteString("}") -+ } else { -+ out.WriteString("\\includegraphics{") -+ out.Write(link) -+ out.WriteString("}") -+ } -+} -+ -+func (options *Latex) LineBreak(out *bytes.Buffer) { -+ out.WriteString(" \\\\\n") -+} -+ -+func (options *Latex) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { -+ out.WriteString("\\href{") -+ out.Write(link) -+ out.WriteString("}{") -+ out.Write(content) -+ out.WriteString("}") -+} -+ -+func (options *Latex) RawHtmlTag(out *bytes.Buffer, tag []byte) { -+} -+ -+func (options *Latex) TripleEmphasis(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\textbf{\\textit{") -+ out.Write(text) -+ out.WriteString("}}") -+} -+ -+func (options *Latex) StrikeThrough(out *bytes.Buffer, text []byte) { -+ out.WriteString("\\sout{") -+ out.Write(text) -+ out.WriteString("}") -+} -+ -+// TODO: this -+func (options *Latex) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { -+ -+} -+ -+func needsBackslash(c byte) bool { -+ for _, r := range []byte("_{}%$&\\~") { -+ if c == r { -+ return true -+ } -+ } -+ return false -+} -+ -+func escapeSpecialChars(out *bytes.Buffer, text []byte) { -+ for i := 0; i < len(text); i++ { -+ // directly copy normal characters -+ org := i -+ -+ for i < len(text) && !needsBackslash(text[i]) { -+ i++ -+ } -+ if i > org { -+ out.Write(text[org:i]) -+ } -+ -+ // escape a character -+ if i >= len(text) { -+ break -+ } -+ out.WriteByte('\\') -+ out.WriteByte(text[i]) -+ } -+} -+ -+func (options *Latex) Entity(out *bytes.Buffer, entity []byte) { -+ // TODO: convert this into a unicode character or something -+ out.Write(entity) -+} -+ -+func (options *Latex) NormalText(out *bytes.Buffer, text []byte) { -+ escapeSpecialChars(out, text) -+} -+ -+// header and footer -+func (options *Latex) DocumentHeader(out *bytes.Buffer) { -+ out.WriteString("\\documentclass{article}\n") -+ out.WriteString("\n") -+ out.WriteString("\\usepackage{graphicx}\n") -+ out.WriteString("\\usepackage{listings}\n") -+ out.WriteString("\\usepackage[margin=1in]{geometry}\n") -+ out.WriteString("\\usepackage[utf8]{inputenc}\n") -+ out.WriteString("\\usepackage{verbatim}\n") -+ out.WriteString("\\usepackage[normalem]{ulem}\n") -+ out.WriteString("\\usepackage{hyperref}\n") -+ out.WriteString("\n") -+ out.WriteString("\\hypersetup{colorlinks,%\n") -+ out.WriteString(" citecolor=black,%\n") -+ out.WriteString(" filecolor=black,%\n") -+ out.WriteString(" linkcolor=black,%\n") -+ out.WriteString(" urlcolor=black,%\n") -+ out.WriteString(" pdfstartview=FitH,%\n") -+ out.WriteString(" breaklinks=true,%\n") -+ out.WriteString(" pdfauthor={Blackfriday Markdown Processor v") -+ out.WriteString(VERSION) -+ out.WriteString("}}\n") -+ out.WriteString("\n") -+ out.WriteString("\\newcommand{\\HRule}{\\rule{\\linewidth}{0.5mm}}\n") -+ out.WriteString("\\addtolength{\\parskip}{0.5\\baselineskip}\n") -+ out.WriteString("\\parindent=0pt\n") -+ out.WriteString("\n") -+ out.WriteString("\\begin{document}\n") -+} -+ -+func (options *Latex) DocumentFooter(out *bytes.Buffer) { -+ out.WriteString("\n\\end{document}\n") -+} -diff --git a/vendor/src/github.com/russross/blackfriday/markdown.go b/vendor/src/github.com/russross/blackfriday/markdown.go -new file mode 100644 -index 0000000..e2cd95b ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/markdown.go -@@ -0,0 +1,838 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// -+// Markdown parsing and processing -+// -+// -+ -+// Blackfriday markdown processor. -+// -+// Translates plain text with simple formatting rules into HTML or LaTeX. -+package blackfriday -+ -+import ( -+ "bytes" -+ "unicode/utf8" -+) -+ -+const VERSION = "1.1" -+ -+// These are the supported markdown parsing extensions. -+// OR these values together to select multiple extensions. -+const ( -+ EXTENSION_NO_INTRA_EMPHASIS = 1 << iota // ignore emphasis markers inside words -+ EXTENSION_TABLES // render tables -+ EXTENSION_FENCED_CODE // render fenced code blocks -+ EXTENSION_AUTOLINK // detect embedded URLs that are not explicitly marked -+ EXTENSION_STRIKETHROUGH // strikethrough text using ~~test~~ -+ EXTENSION_LAX_HTML_BLOCKS // loosen up HTML block parsing rules -+ EXTENSION_SPACE_HEADERS // be strict about prefix header rules -+ EXTENSION_HARD_LINE_BREAK // translate newlines into line breaks -+ EXTENSION_TAB_SIZE_EIGHT // expand tabs to eight spaces instead of four -+ EXTENSION_FOOTNOTES // Pandoc-style footnotes -+ EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK // No need to insert an empty line to start a (code, quote, order list, unorder list)block -+ EXTENSION_HEADER_IDS // specify header IDs with {#id} -+ EXTENSION_TITLEBLOCK // Titleblock ala pandoc -+ EXTENSION_AUTO_HEADER_IDS // Create the header ID from the text -+ EXTENSION_BACKSLASH_LINE_BREAK // translate trailing backslashes into line breaks -+ -+ commonHtmlFlags = 0 | -+ HTML_USE_XHTML | -+ HTML_USE_SMARTYPANTS | -+ HTML_SMARTYPANTS_FRACTIONS | -+ HTML_SMARTYPANTS_LATEX_DASHES -+ -+ commonExtensions = 0 | -+ EXTENSION_NO_INTRA_EMPHASIS | -+ EXTENSION_TABLES | -+ EXTENSION_FENCED_CODE | -+ EXTENSION_AUTOLINK | -+ EXTENSION_STRIKETHROUGH | -+ EXTENSION_SPACE_HEADERS | -+ EXTENSION_HEADER_IDS | -+ EXTENSION_BACKSLASH_LINE_BREAK -+) -+ -+// These are the possible flag values for the link renderer. -+// Only a single one of these values will be used; they are not ORed together. -+// These are mostly of interest if you are writing a new output format. -+const ( -+ LINK_TYPE_NOT_AUTOLINK = iota -+ LINK_TYPE_NORMAL -+ LINK_TYPE_EMAIL -+) -+ -+// These are the possible flag values for the ListItem renderer. -+// Multiple flag values may be ORed together. -+// These are mostly of interest if you are writing a new output format. -+const ( -+ LIST_TYPE_ORDERED = 1 << iota -+ LIST_ITEM_CONTAINS_BLOCK -+ LIST_ITEM_BEGINNING_OF_LIST -+ LIST_ITEM_END_OF_LIST -+) -+ -+// These are the possible flag values for the table cell renderer. -+// Only a single one of these values will be used; they are not ORed together. -+// These are mostly of interest if you are writing a new output format. -+const ( -+ TABLE_ALIGNMENT_LEFT = 1 << iota -+ TABLE_ALIGNMENT_RIGHT -+ TABLE_ALIGNMENT_CENTER = (TABLE_ALIGNMENT_LEFT | TABLE_ALIGNMENT_RIGHT) -+) -+ -+// The size of a tab stop. -+const ( -+ TAB_SIZE_DEFAULT = 4 -+ TAB_SIZE_EIGHT = 8 -+) -+ -+// These are the tags that are recognized as HTML block tags. -+// Any of these can be included in markdown text without special escaping. -+var blockTags = map[string]bool{ -+ "p": true, -+ "dl": true, -+ "h1": true, -+ "h2": true, -+ "h3": true, -+ "h4": true, -+ "h5": true, -+ "h6": true, -+ "ol": true, -+ "ul": true, -+ "del": true, -+ "div": true, -+ "ins": true, -+ "pre": true, -+ "form": true, -+ "math": true, -+ "table": true, -+ "iframe": true, -+ "script": true, -+ "fieldset": true, -+ "noscript": true, -+ "blockquote": true, -+ -+ // HTML5 -+ "video": true, -+ "aside": true, -+ "canvas": true, -+ "figure": true, -+ "footer": true, -+ "header": true, -+ "hgroup": true, -+ "output": true, -+ "article": true, -+ "section": true, -+ "progress": true, -+ "figcaption": true, -+} -+ -+// Renderer is the rendering interface. -+// This is mostly of interest if you are implementing a new rendering format. -+// -+// When a byte slice is provided, it contains the (rendered) contents of the -+// element. -+// -+// When a callback is provided instead, it will write the contents of the -+// respective element directly to the output buffer and return true on success. -+// If the callback returns false, the rendering function should reset the -+// output buffer as though it had never been called. -+// -+// Currently Html and Latex implementations are provided -+type Renderer interface { -+ // block-level callbacks -+ BlockCode(out *bytes.Buffer, text []byte, lang string) -+ BlockQuote(out *bytes.Buffer, text []byte) -+ BlockHtml(out *bytes.Buffer, text []byte) -+ Header(out *bytes.Buffer, text func() bool, level int, id string) -+ HRule(out *bytes.Buffer) -+ List(out *bytes.Buffer, text func() bool, flags int) -+ ListItem(out *bytes.Buffer, text []byte, flags int) -+ Paragraph(out *bytes.Buffer, text func() bool) -+ Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) -+ TableRow(out *bytes.Buffer, text []byte) -+ TableHeaderCell(out *bytes.Buffer, text []byte, flags int) -+ TableCell(out *bytes.Buffer, text []byte, flags int) -+ Footnotes(out *bytes.Buffer, text func() bool) -+ FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) -+ TitleBlock(out *bytes.Buffer, text []byte) -+ -+ // Span-level callbacks -+ AutoLink(out *bytes.Buffer, link []byte, kind int) -+ CodeSpan(out *bytes.Buffer, text []byte) -+ DoubleEmphasis(out *bytes.Buffer, text []byte) -+ Emphasis(out *bytes.Buffer, text []byte) -+ Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) -+ LineBreak(out *bytes.Buffer) -+ Link(out *bytes.Buffer, link []byte, title []byte, content []byte) -+ RawHtmlTag(out *bytes.Buffer, tag []byte) -+ TripleEmphasis(out *bytes.Buffer, text []byte) -+ StrikeThrough(out *bytes.Buffer, text []byte) -+ FootnoteRef(out *bytes.Buffer, ref []byte, id int) -+ -+ // Low-level callbacks -+ Entity(out *bytes.Buffer, entity []byte) -+ NormalText(out *bytes.Buffer, text []byte) -+ -+ // Header and footer -+ DocumentHeader(out *bytes.Buffer) -+ DocumentFooter(out *bytes.Buffer) -+ -+ GetFlags() int -+} -+ -+// Callback functions for inline parsing. One such function is defined -+// for each character that triggers a response when parsing inline data. -+type inlineParser func(p *parser, out *bytes.Buffer, data []byte, offset int) int -+ -+// Parser holds runtime state used by the parser. -+// This is constructed by the Markdown function. -+type parser struct { -+ r Renderer -+ refs map[string]*reference -+ inlineCallback [256]inlineParser -+ flags int -+ nesting int -+ maxNesting int -+ insideLink bool -+ -+ // Footnotes need to be ordered as well as available to quickly check for -+ // presence. If a ref is also a footnote, it's stored both in refs and here -+ // in notes. Slice is nil if footnotes not enabled. -+ notes []*reference -+} -+ -+// -+// -+// Public interface -+// -+// -+ -+// MarkdownBasic is a convenience function for simple rendering. -+// It processes markdown input with no extensions enabled. -+func MarkdownBasic(input []byte) []byte { -+ // set up the HTML renderer -+ htmlFlags := HTML_USE_XHTML -+ renderer := HtmlRenderer(htmlFlags, "", "") -+ -+ // set up the parser -+ extensions := 0 -+ -+ return Markdown(input, renderer, extensions) -+} -+ -+// Call Markdown with most useful extensions enabled -+// MarkdownCommon is a convenience function for simple rendering. -+// It processes markdown input with common extensions enabled, including: -+// -+// * Smartypants processing with smart fractions and LaTeX dashes -+// -+// * Intra-word emphasis suppression -+// -+// * Tables -+// -+// * Fenced code blocks -+// -+// * Autolinking -+// -+// * Strikethrough support -+// -+// * Strict header parsing -+// -+// * Custom Header IDs -+func MarkdownCommon(input []byte) []byte { -+ // set up the HTML renderer -+ renderer := HtmlRenderer(commonHtmlFlags, "", "") -+ return Markdown(input, renderer, commonExtensions) -+} -+ -+// Markdown is the main rendering function. -+// It parses and renders a block of markdown-encoded text. -+// The supplied Renderer is used to format the output, and extensions dictates -+// which non-standard extensions are enabled. -+// -+// To use the supplied Html or LaTeX renderers, see HtmlRenderer and -+// LatexRenderer, respectively. -+func Markdown(input []byte, renderer Renderer, extensions int) []byte { -+ // no point in parsing if we can't render -+ if renderer == nil { -+ return nil -+ } -+ -+ // fill in the render structure -+ p := new(parser) -+ p.r = renderer -+ p.flags = extensions -+ p.refs = make(map[string]*reference) -+ p.maxNesting = 16 -+ p.insideLink = false -+ -+ // register inline parsers -+ p.inlineCallback['*'] = emphasis -+ p.inlineCallback['_'] = emphasis -+ if extensions&EXTENSION_STRIKETHROUGH != 0 { -+ p.inlineCallback['~'] = emphasis -+ } -+ p.inlineCallback['`'] = codeSpan -+ p.inlineCallback['\n'] = lineBreak -+ p.inlineCallback['['] = link -+ p.inlineCallback['<'] = leftAngle -+ p.inlineCallback['\\'] = escape -+ p.inlineCallback['&'] = entity -+ -+ if extensions&EXTENSION_AUTOLINK != 0 { -+ p.inlineCallback[':'] = autoLink -+ } -+ -+ if extensions&EXTENSION_FOOTNOTES != 0 { -+ p.notes = make([]*reference, 0) -+ } -+ -+ first := firstPass(p, input) -+ second := secondPass(p, first) -+ return second -+} -+ -+// first pass: -+// - extract references -+// - expand tabs -+// - normalize newlines -+// - copy everything else -+// - add missing newlines before fenced code blocks -+func firstPass(p *parser, input []byte) []byte { -+ var out bytes.Buffer -+ tabSize := TAB_SIZE_DEFAULT -+ if p.flags&EXTENSION_TAB_SIZE_EIGHT != 0 { -+ tabSize = TAB_SIZE_EIGHT -+ } -+ beg, end := 0, 0 -+ lastLineWasBlank := false -+ lastFencedCodeBlockEnd := 0 -+ for beg < len(input) { // iterate over lines -+ if end = isReference(p, input[beg:], tabSize); end > 0 { -+ beg += end -+ } else { // skip to the next line -+ end = beg -+ for end < len(input) && input[end] != '\n' && input[end] != '\r' { -+ end++ -+ } -+ -+ if p.flags&EXTENSION_FENCED_CODE != 0 { -+ // when last line was none blank and a fenced code block comes after -+ if beg >= lastFencedCodeBlockEnd { -+ if i := p.fencedCode(&out, input[beg:], false); i > 0 { -+ if !lastLineWasBlank { -+ out.WriteByte('\n') // need to inject additional linebreak -+ } -+ lastFencedCodeBlockEnd = beg + i -+ } -+ } -+ lastLineWasBlank = end == beg -+ } -+ -+ // add the line body if present -+ if end > beg { -+ if end < lastFencedCodeBlockEnd { // Do not expand tabs while inside fenced code blocks. -+ out.Write(input[beg:end]) -+ } else { -+ expandTabs(&out, input[beg:end], tabSize) -+ } -+ } -+ out.WriteByte('\n') -+ -+ if end < len(input) && input[end] == '\r' { -+ end++ -+ } -+ if end < len(input) && input[end] == '\n' { -+ end++ -+ } -+ -+ beg = end -+ } -+ } -+ -+ // empty input? -+ if out.Len() == 0 { -+ out.WriteByte('\n') -+ } -+ -+ return out.Bytes() -+} -+ -+// second pass: actual rendering -+func secondPass(p *parser, input []byte) []byte { -+ var output bytes.Buffer -+ -+ p.r.DocumentHeader(&output) -+ p.block(&output, input) -+ -+ if p.flags&EXTENSION_FOOTNOTES != 0 && len(p.notes) > 0 { -+ p.r.Footnotes(&output, func() bool { -+ flags := LIST_ITEM_BEGINNING_OF_LIST -+ for _, ref := range p.notes { -+ var buf bytes.Buffer -+ if ref.hasBlock { -+ flags |= LIST_ITEM_CONTAINS_BLOCK -+ p.block(&buf, ref.title) -+ } else { -+ p.inline(&buf, ref.title) -+ } -+ p.r.FootnoteItem(&output, ref.link, buf.Bytes(), flags) -+ flags &^= LIST_ITEM_BEGINNING_OF_LIST | LIST_ITEM_CONTAINS_BLOCK -+ } -+ -+ return true -+ }) -+ } -+ -+ p.r.DocumentFooter(&output) -+ -+ if p.nesting != 0 { -+ panic("Nesting level did not end at zero") -+ } -+ -+ return output.Bytes() -+} -+ -+// -+// Link references -+// -+// This section implements support for references that (usually) appear -+// as footnotes in a document, and can be referenced anywhere in the document. -+// The basic format is: -+// -+// [1]: http://www.google.com/ "Google" -+// [2]: http://www.github.com/ "Github" -+// -+// Anywhere in the document, the reference can be linked by referring to its -+// label, i.e., 1 and 2 in this example, as in: -+// -+// This library is hosted on [Github][2], a git hosting site. -+// -+// Actual footnotes as specified in Pandoc and supported by some other Markdown -+// libraries such as php-markdown are also taken care of. They look like this: -+// -+// This sentence needs a bit of further explanation.[^note] -+// -+// [^note]: This is the explanation. -+// -+// Footnotes should be placed at the end of the document in an ordered list. -+// Inline footnotes such as: -+// -+// Inline footnotes^[Not supported.] also exist. -+// -+// are not yet supported. -+ -+// References are parsed and stored in this struct. -+type reference struct { -+ link []byte -+ title []byte -+ noteId int // 0 if not a footnote ref -+ hasBlock bool -+} -+ -+// Check whether or not data starts with a reference link. -+// If so, it is parsed and stored in the list of references -+// (in the render struct). -+// Returns the number of bytes to skip to move past it, -+// or zero if the first line is not a reference. -+func isReference(p *parser, data []byte, tabSize int) int { -+ // up to 3 optional leading spaces -+ if len(data) < 4 { -+ return 0 -+ } -+ i := 0 -+ for i < 3 && data[i] == ' ' { -+ i++ -+ } -+ -+ noteId := 0 -+ -+ // id part: anything but a newline between brackets -+ if data[i] != '[' { -+ return 0 -+ } -+ i++ -+ if p.flags&EXTENSION_FOOTNOTES != 0 { -+ if data[i] == '^' { -+ // we can set it to anything here because the proper noteIds will -+ // be assigned later during the second pass. It just has to be != 0 -+ noteId = 1 -+ i++ -+ } -+ } -+ idOffset := i -+ for i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != ']' { -+ i++ -+ } -+ if i >= len(data) || data[i] != ']' { -+ return 0 -+ } -+ idEnd := i -+ -+ // spacer: colon (space | tab)* newline? (space | tab)* -+ i++ -+ if i >= len(data) || data[i] != ':' { -+ return 0 -+ } -+ i++ -+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') { -+ i++ -+ } -+ if i < len(data) && (data[i] == '\n' || data[i] == '\r') { -+ i++ -+ if i < len(data) && data[i] == '\n' && data[i-1] == '\r' { -+ i++ -+ } -+ } -+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') { -+ i++ -+ } -+ if i >= len(data) { -+ return 0 -+ } -+ -+ var ( -+ linkOffset, linkEnd int -+ titleOffset, titleEnd int -+ lineEnd int -+ raw []byte -+ hasBlock bool -+ ) -+ -+ if p.flags&EXTENSION_FOOTNOTES != 0 && noteId != 0 { -+ linkOffset, linkEnd, raw, hasBlock = scanFootnote(p, data, i, tabSize) -+ lineEnd = linkEnd -+ } else { -+ linkOffset, linkEnd, titleOffset, titleEnd, lineEnd = scanLinkRef(p, data, i) -+ } -+ if lineEnd == 0 { -+ return 0 -+ } -+ -+ // a valid ref has been found -+ -+ ref := &reference{ -+ noteId: noteId, -+ hasBlock: hasBlock, -+ } -+ -+ if noteId > 0 { -+ // reusing the link field for the id since footnotes don't have links -+ ref.link = data[idOffset:idEnd] -+ // if footnote, it's not really a title, it's the contained text -+ ref.title = raw -+ } else { -+ ref.link = data[linkOffset:linkEnd] -+ ref.title = data[titleOffset:titleEnd] -+ } -+ -+ // id matches are case-insensitive -+ id := string(bytes.ToLower(data[idOffset:idEnd])) -+ -+ p.refs[id] = ref -+ -+ return lineEnd -+} -+ -+func scanLinkRef(p *parser, data []byte, i int) (linkOffset, linkEnd, titleOffset, titleEnd, lineEnd int) { -+ // link: whitespace-free sequence, optionally between angle brackets -+ if data[i] == '<' { -+ i++ -+ } -+ linkOffset = i -+ for i < len(data) && data[i] != ' ' && data[i] != '\t' && data[i] != '\n' && data[i] != '\r' { -+ i++ -+ } -+ linkEnd = i -+ if data[linkOffset] == '<' && data[linkEnd-1] == '>' { -+ linkOffset++ -+ linkEnd-- -+ } -+ -+ // optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) -+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') { -+ i++ -+ } -+ if i < len(data) && data[i] != '\n' && data[i] != '\r' && data[i] != '\'' && data[i] != '"' && data[i] != '(' { -+ return -+ } -+ -+ // compute end-of-line -+ if i >= len(data) || data[i] == '\r' || data[i] == '\n' { -+ lineEnd = i -+ } -+ if i+1 < len(data) && data[i] == '\r' && data[i+1] == '\n' { -+ lineEnd++ -+ } -+ -+ // optional (space|tab)* spacer after a newline -+ if lineEnd > 0 { -+ i = lineEnd + 1 -+ for i < len(data) && (data[i] == ' ' || data[i] == '\t') { -+ i++ -+ } -+ } -+ -+ // optional title: any non-newline sequence enclosed in '"() alone on its line -+ if i+1 < len(data) && (data[i] == '\'' || data[i] == '"' || data[i] == '(') { -+ i++ -+ titleOffset = i -+ -+ // look for EOL -+ for i < len(data) && data[i] != '\n' && data[i] != '\r' { -+ i++ -+ } -+ if i+1 < len(data) && data[i] == '\n' && data[i+1] == '\r' { -+ titleEnd = i + 1 -+ } else { -+ titleEnd = i -+ } -+ -+ // step back -+ i-- -+ for i > titleOffset && (data[i] == ' ' || data[i] == '\t') { -+ i-- -+ } -+ if i > titleOffset && (data[i] == '\'' || data[i] == '"' || data[i] == ')') { -+ lineEnd = titleEnd -+ titleEnd = i -+ } -+ } -+ -+ return -+} -+ -+// The first bit of this logic is the same as (*parser).listItem, but the rest -+// is much simpler. This function simply finds the entire block and shifts it -+// over by one tab if it is indeed a block (just returns the line if it's not). -+// blockEnd is the end of the section in the input buffer, and contents is the -+// extracted text that was shifted over one tab. It will need to be rendered at -+// the end of the document. -+func scanFootnote(p *parser, data []byte, i, indentSize int) (blockStart, blockEnd int, contents []byte, hasBlock bool) { -+ if i == 0 || len(data) == 0 { -+ return -+ } -+ -+ // skip leading whitespace on first line -+ for i < len(data) && data[i] == ' ' { -+ i++ -+ } -+ -+ blockStart = i -+ -+ // find the end of the line -+ blockEnd = i -+ for i < len(data) && data[i-1] != '\n' { -+ i++ -+ } -+ -+ // get working buffer -+ var raw bytes.Buffer -+ -+ // put the first line into the working buffer -+ raw.Write(data[blockEnd:i]) -+ blockEnd = i -+ -+ // process the following lines -+ containsBlankLine := false -+ -+gatherLines: -+ for blockEnd < len(data) { -+ i++ -+ -+ // find the end of this line -+ for i < len(data) && data[i-1] != '\n' { -+ i++ -+ } -+ -+ // if it is an empty line, guess that it is part of this item -+ // and move on to the next line -+ if p.isEmpty(data[blockEnd:i]) > 0 { -+ containsBlankLine = true -+ blockEnd = i -+ continue -+ } -+ -+ n := 0 -+ if n = isIndented(data[blockEnd:i], indentSize); n == 0 { -+ // this is the end of the block. -+ // we don't want to include this last line in the index. -+ break gatherLines -+ } -+ -+ // if there were blank lines before this one, insert a new one now -+ if containsBlankLine { -+ raw.WriteByte('\n') -+ containsBlankLine = false -+ } -+ -+ // get rid of that first tab, write to buffer -+ raw.Write(data[blockEnd+n : i]) -+ hasBlock = true -+ -+ blockEnd = i -+ } -+ -+ if data[blockEnd-1] != '\n' { -+ raw.WriteByte('\n') -+ } -+ -+ contents = raw.Bytes() -+ -+ return -+} -+ -+// -+// -+// Miscellaneous helper functions -+// -+// -+ -+// Test if a character is a punctuation symbol. -+// Taken from a private function in regexp in the stdlib. -+func ispunct(c byte) bool { -+ for _, r := range []byte("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~") { -+ if c == r { -+ return true -+ } -+ } -+ return false -+} -+ -+// Test if a character is a whitespace character. -+func isspace(c byte) bool { -+ return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v' -+} -+ -+// Test if a character is letter. -+func isletter(c byte) bool { -+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') -+} -+ -+// Test if a character is a letter or a digit. -+// TODO: check when this is looking for ASCII alnum and when it should use unicode -+func isalnum(c byte) bool { -+ return (c >= '0' && c <= '9') || isletter(c) -+} -+ -+// Replace tab characters with spaces, aligning to the next TAB_SIZE column. -+// always ends output with a newline -+func expandTabs(out *bytes.Buffer, line []byte, tabSize int) { -+ // first, check for common cases: no tabs, or only tabs at beginning of line -+ i, prefix := 0, 0 -+ slowcase := false -+ for i = 0; i < len(line); i++ { -+ if line[i] == '\t' { -+ if prefix == i { -+ prefix++ -+ } else { -+ slowcase = true -+ break -+ } -+ } -+ } -+ -+ // no need to decode runes if all tabs are at the beginning of the line -+ if !slowcase { -+ for i = 0; i < prefix*tabSize; i++ { -+ out.WriteByte(' ') -+ } -+ out.Write(line[prefix:]) -+ return -+ } -+ -+ // the slow case: we need to count runes to figure out how -+ // many spaces to insert for each tab -+ column := 0 -+ i = 0 -+ for i < len(line) { -+ start := i -+ for i < len(line) && line[i] != '\t' { -+ _, size := utf8.DecodeRune(line[i:]) -+ i += size -+ column++ -+ } -+ -+ if i > start { -+ out.Write(line[start:i]) -+ } -+ -+ if i >= len(line) { -+ break -+ } -+ -+ for { -+ out.WriteByte(' ') -+ column++ -+ if column%tabSize == 0 { -+ break -+ } -+ } -+ -+ i++ -+ } -+} -+ -+// Find if a line counts as indented or not. -+// Returns number of characters the indent is (0 = not indented). -+func isIndented(data []byte, indentSize int) int { -+ if len(data) == 0 { -+ return 0 -+ } -+ if data[0] == '\t' { -+ return 1 -+ } -+ if len(data) < indentSize { -+ return 0 -+ } -+ for i := 0; i < indentSize; i++ { -+ if data[i] != ' ' { -+ return 0 -+ } -+ } -+ return indentSize -+} -+ -+// Create a url-safe slug for fragments -+func slugify(in []byte) []byte { -+ if len(in) == 0 { -+ return in -+ } -+ out := make([]byte, 0, len(in)) -+ sym := false -+ -+ for _, ch := range in { -+ if isalnum(ch) { -+ sym = false -+ out = append(out, ch) -+ } else if sym { -+ continue -+ } else { -+ out = append(out, '-') -+ sym = true -+ } -+ } -+ var a, b int -+ var ch byte -+ for a, ch = range out { -+ if ch != '-' { -+ break -+ } -+ } -+ for b = len(out) - 1; b > 0; b-- { -+ if out[b] != '-' { -+ break -+ } -+ } -+ return out[a : b+1] -+} -diff --git a/vendor/src/github.com/russross/blackfriday/ref_test.go b/vendor/src/github.com/russross/blackfriday/ref_test.go -new file mode 100644 -index 0000000..770439c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/ref_test.go -@@ -0,0 +1,128 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// Markdown 1.0.3 reference tests -+// -+ -+package blackfriday -+ -+import ( -+ "io/ioutil" -+ "path/filepath" -+ "testing" -+) -+ -+func runMarkdownReference(input string, flag int) string { -+ renderer := HtmlRenderer(0, "", "") -+ return string(Markdown([]byte(input), renderer, flag)) -+} -+ -+func doTestsReference(t *testing.T, files []string, flag int) { -+ // catch and report panics -+ var candidate string -+ defer func() { -+ if err := recover(); err != nil { -+ t.Errorf("\npanic while processing [%#v]\n", candidate) -+ } -+ }() -+ -+ for _, basename := range files { -+ filename := filepath.Join("testdata", basename+".text") -+ inputBytes, err := ioutil.ReadFile(filename) -+ if err != nil { -+ t.Errorf("Couldn't open '%s', error: %v\n", filename, err) -+ continue -+ } -+ input := string(inputBytes) -+ -+ filename = filepath.Join("testdata", basename+".html") -+ expectedBytes, err := ioutil.ReadFile(filename) -+ if err != nil { -+ t.Errorf("Couldn't open '%s', error: %v\n", filename, err) -+ continue -+ } -+ expected := string(expectedBytes) -+ -+ // fmt.Fprintf(os.Stderr, "processing %s ...", filename) -+ actual := string(runMarkdownReference(input, flag)) -+ if actual != expected { -+ t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]", -+ basename+".text", expected, actual) -+ } -+ // fmt.Fprintf(os.Stderr, " ok\n") -+ -+ // now test every prefix of every input to check for -+ // bounds checking -+ if !testing.Short() { -+ start, max := 0, len(input) -+ for end := start + 1; end <= max; end++ { -+ candidate = input[start:end] -+ // fmt.Fprintf(os.Stderr, " %s %d:%d/%d\n", filename, start, end, max) -+ _ = runMarkdownReference(candidate, flag) -+ } -+ } -+ } -+} -+ -+func TestReference(t *testing.T) { -+ files := []string{ -+ "Amps and angle encoding", -+ "Auto links", -+ "Backslash escapes", -+ "Blockquotes with code blocks", -+ "Code Blocks", -+ "Code Spans", -+ "Hard-wrapped paragraphs with list-like lines", -+ "Horizontal rules", -+ "Inline HTML (Advanced)", -+ "Inline HTML (Simple)", -+ "Inline HTML comments", -+ "Links, inline style", -+ "Links, reference style", -+ "Links, shortcut references", -+ "Literal quotes in titles", -+ "Markdown Documentation - Basics", -+ "Markdown Documentation - Syntax", -+ "Nested blockquotes", -+ "Ordered and unordered lists", -+ "Strong and em together", -+ "Tabs", -+ "Tidyness", -+ } -+ doTestsReference(t, files, 0) -+} -+ -+func TestReference_EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK(t *testing.T) { -+ files := []string{ -+ "Amps and angle encoding", -+ "Auto links", -+ "Backslash escapes", -+ "Blockquotes with code blocks", -+ "Code Blocks", -+ "Code Spans", -+ "Hard-wrapped paragraphs with list-like lines no empty line before block", -+ "Horizontal rules", -+ "Inline HTML (Advanced)", -+ "Inline HTML (Simple)", -+ "Inline HTML comments", -+ "Links, inline style", -+ "Links, reference style", -+ "Links, shortcut references", -+ "Literal quotes in titles", -+ "Markdown Documentation - Basics", -+ "Markdown Documentation - Syntax", -+ "Nested blockquotes", -+ "Ordered and unordered lists", -+ "Strong and em together", -+ "Tabs", -+ "Tidyness", -+ } -+ doTestsReference(t, files, EXTENSION_NO_EMPTY_LINE_BEFORE_BLOCK) -+} -diff --git a/vendor/src/github.com/russross/blackfriday/smartypants.go b/vendor/src/github.com/russross/blackfriday/smartypants.go -new file mode 100644 -index 0000000..8027571 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/smartypants.go -@@ -0,0 +1,398 @@ -+// -+// Blackfriday Markdown Processor -+// Available at http://github.com/russross/blackfriday -+// -+// Copyright © 2011 Russ Ross <russ@russross.com>. -+// Distributed under the Simplified BSD License. -+// See README.md for details. -+// -+ -+// -+// -+// SmartyPants rendering -+// -+// -+ -+package blackfriday -+ -+import ( -+ "bytes" -+) -+ -+type smartypantsData struct { -+ inSingleQuote bool -+ inDoubleQuote bool -+} -+ -+func wordBoundary(c byte) bool { -+ return c == 0 || isspace(c) || ispunct(c) -+} -+ -+func tolower(c byte) byte { -+ if c >= 'A' && c <= 'Z' { -+ return c - 'A' + 'a' -+ } -+ return c -+} -+ -+func isdigit(c byte) bool { -+ return c >= '0' && c <= '9' -+} -+ -+func smartQuoteHelper(out *bytes.Buffer, previousChar byte, nextChar byte, quote byte, isOpen *bool) bool { -+ // edge of the buffer is likely to be a tag that we don't get to see, -+ // so we treat it like text sometimes -+ -+ // enumerate all sixteen possibilities for (previousChar, nextChar) -+ // each can be one of {0, space, punct, other} -+ switch { -+ case previousChar == 0 && nextChar == 0: -+ // context is not any help here, so toggle -+ *isOpen = !*isOpen -+ case isspace(previousChar) && nextChar == 0: -+ // [ "] might be [ "<code>foo...] -+ *isOpen = true -+ case ispunct(previousChar) && nextChar == 0: -+ // [!"] hmm... could be [Run!"] or [("<code>...] -+ *isOpen = false -+ case /* isnormal(previousChar) && */ nextChar == 0: -+ // [a"] is probably a close -+ *isOpen = false -+ case previousChar == 0 && isspace(nextChar): -+ // [" ] might be [...foo</code>" ] -+ *isOpen = false -+ case isspace(previousChar) && isspace(nextChar): -+ // [ " ] context is not any help here, so toggle -+ *isOpen = !*isOpen -+ case ispunct(previousChar) && isspace(nextChar): -+ // [!" ] is probably a close -+ *isOpen = false -+ case /* isnormal(previousChar) && */ isspace(nextChar): -+ // [a" ] this is one of the easy cases -+ *isOpen = false -+ case previousChar == 0 && ispunct(nextChar): -+ // ["!] hmm... could be ["$1.95] or [</code>"!...] -+ *isOpen = false -+ case isspace(previousChar) && ispunct(nextChar): -+ // [ "!] looks more like [ "$1.95] -+ *isOpen = true -+ case ispunct(previousChar) && ispunct(nextChar): -+ // [!"!] context is not any help here, so toggle -+ *isOpen = !*isOpen -+ case /* isnormal(previousChar) && */ ispunct(nextChar): -+ // [a"!] is probably a close -+ *isOpen = false -+ case previousChar == 0 /* && isnormal(nextChar) */ : -+ // ["a] is probably an open -+ *isOpen = true -+ case isspace(previousChar) /* && isnormal(nextChar) */ : -+ // [ "a] this is one of the easy cases -+ *isOpen = true -+ case ispunct(previousChar) /* && isnormal(nextChar) */ : -+ // [!"a] is probably an open -+ *isOpen = true -+ default: -+ // [a'b] maybe a contraction? -+ *isOpen = false -+ } -+ -+ out.WriteByte('&') -+ if *isOpen { -+ out.WriteByte('l') -+ } else { -+ out.WriteByte('r') -+ } -+ out.WriteByte(quote) -+ out.WriteString("quo;") -+ return true -+} -+ -+func smartSingleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 2 { -+ t1 := tolower(text[1]) -+ -+ if t1 == '\'' { -+ nextChar := byte(0) -+ if len(text) >= 3 { -+ nextChar = text[2] -+ } -+ if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { -+ return 1 -+ } -+ } -+ -+ if (t1 == 's' || t1 == 't' || t1 == 'm' || t1 == 'd') && (len(text) < 3 || wordBoundary(text[2])) { -+ out.WriteString("’") -+ return 0 -+ } -+ -+ if len(text) >= 3 { -+ t2 := tolower(text[2]) -+ -+ if ((t1 == 'r' && t2 == 'e') || (t1 == 'l' && t2 == 'l') || (t1 == 'v' && t2 == 'e')) && -+ (len(text) < 4 || wordBoundary(text[3])) { -+ out.WriteString("’") -+ return 0 -+ } -+ } -+ } -+ -+ nextChar := byte(0) -+ if len(text) > 1 { -+ nextChar = text[1] -+ } -+ if smartQuoteHelper(out, previousChar, nextChar, 's', &smrt.inSingleQuote) { -+ return 0 -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartParens(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 3 { -+ t1 := tolower(text[1]) -+ t2 := tolower(text[2]) -+ -+ if t1 == 'c' && t2 == ')' { -+ out.WriteString("©") -+ return 2 -+ } -+ -+ if t1 == 'r' && t2 == ')' { -+ out.WriteString("®") -+ return 2 -+ } -+ -+ if len(text) >= 4 && t1 == 't' && t2 == 'm' && text[3] == ')' { -+ out.WriteString("™") -+ return 3 -+ } -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartDash(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 2 { -+ if text[1] == '-' { -+ out.WriteString("—") -+ return 1 -+ } -+ -+ if wordBoundary(previousChar) && wordBoundary(text[1]) { -+ out.WriteString("–") -+ return 0 -+ } -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartDashLatex(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 3 && text[1] == '-' && text[2] == '-' { -+ out.WriteString("—") -+ return 2 -+ } -+ if len(text) >= 2 && text[1] == '-' { -+ out.WriteString("–") -+ return 1 -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartAmpVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int { -+ if bytes.HasPrefix(text, []byte(""")) { -+ nextChar := byte(0) -+ if len(text) >= 7 { -+ nextChar = text[6] -+ } -+ if smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) { -+ return 5 -+ } -+ } -+ -+ if bytes.HasPrefix(text, []byte("�")) { -+ return 3 -+ } -+ -+ out.WriteByte('&') -+ return 0 -+} -+ -+func smartAmp(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ return smartAmpVariant(out, smrt, previousChar, text, 'd') -+} -+ -+func smartAmpAngledQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ return smartAmpVariant(out, smrt, previousChar, text, 'a') -+} -+ -+func smartPeriod(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 3 && text[1] == '.' && text[2] == '.' { -+ out.WriteString("…") -+ return 2 -+ } -+ -+ if len(text) >= 5 && text[1] == ' ' && text[2] == '.' && text[3] == ' ' && text[4] == '.' { -+ out.WriteString("…") -+ return 4 -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartBacktick(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if len(text) >= 2 && text[1] == '`' { -+ nextChar := byte(0) -+ if len(text) >= 3 { -+ nextChar = text[2] -+ } -+ if smartQuoteHelper(out, previousChar, nextChar, 'd', &smrt.inDoubleQuote) { -+ return 1 -+ } -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartNumberGeneric(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { -+ // is it of the form digits/digits(word boundary)?, i.e., \d+/\d+\b -+ // note: check for regular slash (/) or fraction slash (⁄, 0x2044, or 0xe2 81 84 in utf-8) -+ // and avoid changing dates like 1/23/2005 into fractions. -+ numEnd := 0 -+ for len(text) > numEnd && isdigit(text[numEnd]) { -+ numEnd++ -+ } -+ if numEnd == 0 { -+ out.WriteByte(text[0]) -+ return 0 -+ } -+ denStart := numEnd + 1 -+ if len(text) > numEnd+3 && text[numEnd] == 0xe2 && text[numEnd+1] == 0x81 && text[numEnd+2] == 0x84 { -+ denStart = numEnd + 3 -+ } else if len(text) < numEnd+2 || text[numEnd] != '/' { -+ out.WriteByte(text[0]) -+ return 0 -+ } -+ denEnd := denStart -+ for len(text) > denEnd && isdigit(text[denEnd]) { -+ denEnd++ -+ } -+ if denEnd == denStart { -+ out.WriteByte(text[0]) -+ return 0 -+ } -+ if len(text) == denEnd || wordBoundary(text[denEnd]) && text[denEnd] != '/' { -+ out.WriteString("<sup>") -+ out.Write(text[:numEnd]) -+ out.WriteString("</sup>⁄<sub>") -+ out.Write(text[denStart:denEnd]) -+ out.WriteString("</sub>") -+ return denEnd - 1 -+ } -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartNumber(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ if wordBoundary(previousChar) && previousChar != '/' && len(text) >= 3 { -+ if text[0] == '1' && text[1] == '/' && text[2] == '2' { -+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' { -+ out.WriteString("½") -+ return 2 -+ } -+ } -+ -+ if text[0] == '1' && text[1] == '/' && text[2] == '4' { -+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h') { -+ out.WriteString("¼") -+ return 2 -+ } -+ } -+ -+ if text[0] == '3' && text[1] == '/' && text[2] == '4' { -+ if len(text) < 4 || wordBoundary(text[3]) && text[3] != '/' || (len(text) >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's') { -+ out.WriteString("¾") -+ return 2 -+ } -+ } -+ } -+ -+ out.WriteByte(text[0]) -+ return 0 -+} -+ -+func smartDoubleQuoteVariant(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte, quote byte) int { -+ nextChar := byte(0) -+ if len(text) > 1 { -+ nextChar = text[1] -+ } -+ if !smartQuoteHelper(out, previousChar, nextChar, quote, &smrt.inDoubleQuote) { -+ out.WriteString(""") -+ } -+ -+ return 0 -+} -+ -+func smartDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'd') -+} -+ -+func smartAngledDoubleQuote(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ return smartDoubleQuoteVariant(out, smrt, previousChar, text, 'a') -+} -+ -+func smartLeftAngle(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int { -+ i := 0 -+ -+ for i < len(text) && text[i] != '>' { -+ i++ -+ } -+ -+ out.Write(text[:i+1]) -+ return i -+} -+ -+type smartCallback func(out *bytes.Buffer, smrt *smartypantsData, previousChar byte, text []byte) int -+ -+type smartypantsRenderer [256]smartCallback -+ -+func smartypants(flags int) *smartypantsRenderer { -+ r := new(smartypantsRenderer) -+ if flags&HTML_SMARTYPANTS_ANGLED_QUOTES == 0 { -+ r['"'] = smartDoubleQuote -+ r['&'] = smartAmp -+ } else { -+ r['"'] = smartAngledDoubleQuote -+ r['&'] = smartAmpAngledQuote -+ } -+ r['\''] = smartSingleQuote -+ r['('] = smartParens -+ if flags&HTML_SMARTYPANTS_LATEX_DASHES == 0 { -+ r['-'] = smartDash -+ } else { -+ r['-'] = smartDashLatex -+ } -+ r['.'] = smartPeriod -+ if flags&HTML_SMARTYPANTS_FRACTIONS == 0 { -+ r['1'] = smartNumber -+ r['3'] = smartNumber -+ } else { -+ for ch := '1'; ch <= '9'; ch++ { -+ r[ch] = smartNumberGeneric -+ } -+ } -+ r['<'] = smartLeftAngle -+ r['`'] = smartBacktick -+ return r -+} -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html -new file mode 100644 -index 0000000..483f8ff ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.html -@@ -0,0 +1,17 @@ -+<p>AT&T has an ampersand in their name.</p> -+ -+<p>AT&T is another way to write it.</p> -+ -+<p>This & that.</p> -+ -+<p>4 < 5.</p> -+ -+<p>6 > 5.</p> -+ -+<p>Here's a <a href="http://example.com/?foo=1&bar=2">link</a> with an ampersand in the URL.</p> -+ -+<p>Here's a link with an amersand in the link text: <a href="http://att.com/" title="AT&T">AT&T</a>.</p> -+ -+<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p> -+ -+<p>Here's an inline <a href="/script?foo=1&bar=2">link</a>.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text -new file mode 100644 -index 0000000..0e9527f ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Amps and angle encoding.text -@@ -0,0 +1,21 @@ -+AT&T has an ampersand in their name. -+ -+AT&T is another way to write it. -+ -+This & that. -+ -+4 < 5. -+ -+6 > 5. -+ -+Here's a [link] [1] with an ampersand in the URL. -+ -+Here's a link with an amersand in the link text: [AT&T] [2]. -+ -+Here's an inline [link](/script?foo=1&bar=2). -+ -+Here's an inline [link](</script?foo=1&bar=2>). -+ -+ -+[1]: http://example.com/?foo=1&bar=2 -+[2]: http://att.com/ "AT&T" -\ No newline at end of file -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html -new file mode 100644 -index 0000000..b1791e7 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.html -@@ -0,0 +1,18 @@ -+<p>Link: <a href="http://example.com/">http://example.com/</a>.</p> -+ -+<p>With an ampersand: <a href="http://example.com/?foo=1&bar=2">http://example.com/?foo=1&bar=2</a></p> -+ -+<ul> -+<li>In a list?</li> -+<li><a href="http://example.com/">http://example.com/</a></li> -+<li>It should.</li> -+</ul> -+ -+<blockquote> -+<p>Blockquoted: <a href="http://example.com/">http://example.com/</a></p> -+</blockquote> -+ -+<p>Auto-links should not occur here: <code><http://example.com/></code></p> -+ -+<pre><code>or here: <http://example.com/> -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text -new file mode 100644 -index 0000000..abbc488 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Auto links.text -@@ -0,0 +1,13 @@ -+Link: <http://example.com/>. -+ -+With an ampersand: <http://example.com/?foo=1&bar=2> -+ -+* In a list? -+* <http://example.com/> -+* It should. -+ -+> Blockquoted: <http://example.com/> -+ -+Auto-links should not occur here: `<http://example.com/>` -+ -+ or here: <http://example.com/> -\ No newline at end of file -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html -new file mode 100644 -index 0000000..a73c998 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.html -@@ -0,0 +1,123 @@ -+<p>These should all get escaped:</p> -+ -+<p>Backslash: \</p> -+ -+<p>Backtick: `</p> -+ -+<p>Asterisk: *</p> -+ -+<p>Underscore: _</p> -+ -+<p>Left brace: {</p> -+ -+<p>Right brace: }</p> -+ -+<p>Left bracket: [</p> -+ -+<p>Right bracket: ]</p> -+ -+<p>Left paren: (</p> -+ -+<p>Right paren: )</p> -+ -+<p>Greater-than: ></p> -+ -+<p>Hash: #</p> -+ -+<p>Period: .</p> -+ -+<p>Bang: !</p> -+ -+<p>Plus: +</p> -+ -+<p>Minus: -</p> -+ -+<p>Tilde: ~</p> -+ -+<p>These should not, because they occur within a code block:</p> -+ -+<pre><code>Backslash: \\ -+ -+Backtick: \` -+ -+Asterisk: \* -+ -+Underscore: \_ -+ -+Left brace: \{ -+ -+Right brace: \} -+ -+Left bracket: \[ -+ -+Right bracket: \] -+ -+Left paren: \( -+ -+Right paren: \) -+ -+Greater-than: \> -+ -+Hash: \# -+ -+Period: \. -+ -+Bang: \! -+ -+Plus: \+ -+ -+Minus: \- -+ -+Tilde: \~ -+</code></pre> -+ -+<p>Nor should these, which occur in code spans:</p> -+ -+<p>Backslash: <code>\\</code></p> -+ -+<p>Backtick: <code>\`</code></p> -+ -+<p>Asterisk: <code>\*</code></p> -+ -+<p>Underscore: <code>\_</code></p> -+ -+<p>Left brace: <code>\{</code></p> -+ -+<p>Right brace: <code>\}</code></p> -+ -+<p>Left bracket: <code>\[</code></p> -+ -+<p>Right bracket: <code>\]</code></p> -+ -+<p>Left paren: <code>\(</code></p> -+ -+<p>Right paren: <code>\)</code></p> -+ -+<p>Greater-than: <code>\></code></p> -+ -+<p>Hash: <code>\#</code></p> -+ -+<p>Period: <code>\.</code></p> -+ -+<p>Bang: <code>\!</code></p> -+ -+<p>Plus: <code>\+</code></p> -+ -+<p>Minus: <code>\-</code></p> -+ -+<p>Tilde: <code>\~</code></p> -+ -+<p>These should get escaped, even though they're matching pairs for -+other Markdown constructs:</p> -+ -+<p>*asterisks*</p> -+ -+<p>_underscores_</p> -+ -+<p>`backticks`</p> -+ -+<p>This is a code span with a literal backslash-backtick sequence: <code>\`</code></p> -+ -+<p>This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>.</p> -+ -+<p>This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text -new file mode 100644 -index 0000000..04c20bd ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Backslash escapes.text -@@ -0,0 +1,126 @@ -+These should all get escaped: -+ -+Backslash: \\ -+ -+Backtick: \` -+ -+Asterisk: \* -+ -+Underscore: \_ -+ -+Left brace: \{ -+ -+Right brace: \} -+ -+Left bracket: \[ -+ -+Right bracket: \] -+ -+Left paren: \( -+ -+Right paren: \) -+ -+Greater-than: \> -+ -+Hash: \# -+ -+Period: \. -+ -+Bang: \! -+ -+Plus: \+ -+ -+Minus: \- -+ -+Tilde: \~ -+ -+ -+ -+These should not, because they occur within a code block: -+ -+ Backslash: \\ -+ -+ Backtick: \` -+ -+ Asterisk: \* -+ -+ Underscore: \_ -+ -+ Left brace: \{ -+ -+ Right brace: \} -+ -+ Left bracket: \[ -+ -+ Right bracket: \] -+ -+ Left paren: \( -+ -+ Right paren: \) -+ -+ Greater-than: \> -+ -+ Hash: \# -+ -+ Period: \. -+ -+ Bang: \! -+ -+ Plus: \+ -+ -+ Minus: \- -+ -+ Tilde: \~ -+ -+ -+Nor should these, which occur in code spans: -+ -+Backslash: `\\` -+ -+Backtick: `` \` `` -+ -+Asterisk: `\*` -+ -+Underscore: `\_` -+ -+Left brace: `\{` -+ -+Right brace: `\}` -+ -+Left bracket: `\[` -+ -+Right bracket: `\]` -+ -+Left paren: `\(` -+ -+Right paren: `\)` -+ -+Greater-than: `\>` -+ -+Hash: `\#` -+ -+Period: `\.` -+ -+Bang: `\!` -+ -+Plus: `\+` -+ -+Minus: `\-` -+ -+Tilde: `\~` -+ -+ -+These should get escaped, even though they're matching pairs for -+other Markdown constructs: -+ -+\*asterisks\* -+ -+\_underscores\_ -+ -+\`backticks\` -+ -+This is a code span with a literal backslash-backtick sequence: `` \` `` -+ -+This is a tag with unescaped backticks <span attr='`ticks`'>bar</span>. -+ -+This is a tag with backslashes <span attr='\\backslashes\\'>bar</span>. -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html -new file mode 100644 -index 0000000..360fa9b ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.html -@@ -0,0 +1,15 @@ -+<blockquote> -+<p>Example:</p> -+ -+<pre><code>sub status { -+ print "working"; -+} -+</code></pre> -+ -+<p>Or:</p> -+ -+<pre><code>sub status { -+ return "working"; -+} -+</code></pre> -+</blockquote> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text -new file mode 100644 -index 0000000..c31d171 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Blockquotes with code blocks.text -@@ -0,0 +1,11 @@ -+> Example: -+> -+> sub status { -+> print "working"; -+> } -+> -+> Or: -+> -+> sub status { -+> return "working"; -+> } -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html -new file mode 100644 -index 0000000..32703f5 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.html -@@ -0,0 +1,18 @@ -+<pre><code>code block on the first line -+</code></pre> -+ -+<p>Regular text.</p> -+ -+<pre><code>code block indented by spaces -+</code></pre> -+ -+<p>Regular text.</p> -+ -+<pre><code>the lines in this block -+all contain trailing spaces -+</code></pre> -+ -+<p>Regular Text.</p> -+ -+<pre><code>code block on the last line -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text -new file mode 100644 -index 0000000..b54b092 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Blocks.text -@@ -0,0 +1,14 @@ -+ code block on the first line -+ -+Regular text. -+ -+ code block indented by spaces -+ -+Regular text. -+ -+ the lines in this block -+ all contain trailing spaces -+ -+Regular Text. -+ -+ code block on the last line -\ No newline at end of file -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html -new file mode 100644 -index 0000000..ef85f95 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.html -@@ -0,0 +1,5 @@ -+<p><code><test a="</code> content of attribute <code>"></code></p> -+ -+<p>Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span></p> -+ -+<p>Here's how you put <code>`backticks`</code> in a code span.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text -new file mode 100644 -index 0000000..750a197 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Code Spans.text -@@ -0,0 +1,6 @@ -+`<test a="` content of attribute `">` -+ -+Fix for backticks within HTML tag: <span attr='`ticks`'>like this</span> -+ -+Here's how you put `` `backticks` `` in a code span. -+ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html -new file mode 100644 -index 0000000..fc25319 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.html -@@ -0,0 +1,14 @@ -+<p>In Markdown 1.0.0 and earlier. Version</p> -+ -+<ol> -+<li>This line turns into a list item. -+Because a hard-wrapped line in the -+middle of a paragraph looked like a -+list item.</li> -+</ol> -+ -+<p>Here's one with a bullet.</p> -+ -+<ul> -+<li>criminey.</li> -+</ul> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text -new file mode 100644 -index 0000000..f8a5b27 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines no empty line before block.text -@@ -0,0 +1,8 @@ -+In Markdown 1.0.0 and earlier. Version -+8. This line turns into a list item. -+Because a hard-wrapped line in the -+middle of a paragraph looked like a -+list item. -+ -+Here's one with a bullet. -+* criminey. -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html -new file mode 100644 -index 0000000..e21ac79 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.html -@@ -0,0 +1,8 @@ -+<p>In Markdown 1.0.0 and earlier. Version -+8. This line turns into a list item. -+Because a hard-wrapped line in the -+middle of a paragraph looked like a -+list item.</p> -+ -+<p>Here's one with a bullet. -+* criminey.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text -new file mode 100644 -index 0000000..f8a5b27 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Hard-wrapped paragraphs with list-like lines.text -@@ -0,0 +1,8 @@ -+In Markdown 1.0.0 and earlier. Version -+8. This line turns into a list item. -+Because a hard-wrapped line in the -+middle of a paragraph looked like a -+list item. -+ -+Here's one with a bullet. -+* criminey. -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html -new file mode 100644 -index 0000000..e60d4ba ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.html -@@ -0,0 +1,71 @@ -+<p>Dashes:</p> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>--- -+</code></pre> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>- - - -+</code></pre> -+ -+<p>Asterisks:</p> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>*** -+</code></pre> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>* * * -+</code></pre> -+ -+<p>Underscores:</p> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>___ -+</code></pre> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<hr> -+ -+<pre><code>_ _ _ -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text -new file mode 100644 -index 0000000..1594bda ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Horizontal rules.text -@@ -0,0 +1,67 @@ -+Dashes: -+ -+--- -+ -+ --- -+ -+ --- -+ -+ --- -+ -+ --- -+ -+- - - -+ -+ - - - -+ -+ - - - -+ -+ - - - -+ -+ - - - -+ -+ -+Asterisks: -+ -+*** -+ -+ *** -+ -+ *** -+ -+ *** -+ -+ *** -+ -+* * * -+ -+ * * * -+ -+ * * * -+ -+ * * * -+ -+ * * * -+ -+ -+Underscores: -+ -+___ -+ -+ ___ -+ -+ ___ -+ -+ ___ -+ -+ ___ -+ -+_ _ _ -+ -+ _ _ _ -+ -+ _ _ _ -+ -+ _ _ _ -+ -+ _ _ _ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html -new file mode 100644 -index 0000000..3af9caf ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).html -@@ -0,0 +1,15 @@ -+<p>Simple block on one line:</p> -+ -+<div>foo</div> -+ -+<p>And nested without indentation:</p> -+ -+<div> -+<div> -+<div> -+foo -+</div> -+<div style=">"/> -+</div> -+<div>bar</div> -+</div> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text -new file mode 100644 -index 0000000..86b7206 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Advanced).text -@@ -0,0 +1,15 @@ -+Simple block on one line: -+ -+<div>foo</div> -+ -+And nested without indentation: -+ -+<div> -+<div> -+<div> -+foo -+</div> -+<div style=">"/> -+</div> -+<div>bar</div> -+</div> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html -new file mode 100644 -index 0000000..6bf78f8 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).html -@@ -0,0 +1,72 @@ -+<p>Here's a simple block:</p> -+ -+<div> -+ foo -+</div> -+ -+<p>This should be a code block, though:</p> -+ -+<pre><code><div> -+ foo -+</div> -+</code></pre> -+ -+<p>As should this:</p> -+ -+<pre><code><div>foo</div> -+</code></pre> -+ -+<p>Now, nested:</p> -+ -+<div> -+ <div> -+ <div> -+ foo -+ </div> -+ </div> -+</div> -+ -+<p>This should just be an HTML comment:</p> -+ -+<!-- Comment --> -+ -+<p>Multiline:</p> -+ -+<!-- -+Blah -+Blah -+--> -+ -+<p>Code block:</p> -+ -+<pre><code><!-- Comment --> -+</code></pre> -+ -+<p>Just plain comment, with trailing spaces on the line:</p> -+ -+<!-- foo --> -+ -+<p>Code:</p> -+ -+<pre><code><hr /> -+</code></pre> -+ -+<p>Hr's:</p> -+ -+<hr> -+ -+<hr/> -+ -+<hr /> -+ -+<hr> -+ -+<hr/> -+ -+<hr /> -+ -+<hr class="foo" id="bar" /> -+ -+<hr class="foo" id="bar"/> -+ -+<hr class="foo" id="bar" > -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text -new file mode 100644 -index 0000000..14aa2dc ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML (Simple).text -@@ -0,0 +1,69 @@ -+Here's a simple block: -+ -+<div> -+ foo -+</div> -+ -+This should be a code block, though: -+ -+ <div> -+ foo -+ </div> -+ -+As should this: -+ -+ <div>foo</div> -+ -+Now, nested: -+ -+<div> -+ <div> -+ <div> -+ foo -+ </div> -+ </div> -+</div> -+ -+This should just be an HTML comment: -+ -+<!-- Comment --> -+ -+Multiline: -+ -+<!-- -+Blah -+Blah -+--> -+ -+Code block: -+ -+ <!-- Comment --> -+ -+Just plain comment, with trailing spaces on the line: -+ -+<!-- foo --> -+ -+Code: -+ -+ <hr /> -+ -+Hr's: -+ -+<hr> -+ -+<hr/> -+ -+<hr /> -+ -+<hr> -+ -+<hr/> -+ -+<hr /> -+ -+<hr class="foo" id="bar" /> -+ -+<hr class="foo" id="bar"/> -+ -+<hr class="foo" id="bar" > -+ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html -new file mode 100644 -index 0000000..3f167a1 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.html -@@ -0,0 +1,13 @@ -+<p>Paragraph one.</p> -+ -+<!-- This is a simple comment --> -+ -+<!-- -+ This is another comment. -+--> -+ -+<p>Paragraph two.</p> -+ -+<!-- one comment block -- -- with two comments --> -+ -+<p>The end.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text -new file mode 100644 -index 0000000..41d830d ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Inline HTML comments.text -@@ -0,0 +1,13 @@ -+Paragraph one. -+ -+<!-- This is a simple comment --> -+ -+<!-- -+ This is another comment. -+--> -+ -+Paragraph two. -+ -+<!-- one comment block -- -- with two comments --> -+ -+The end. -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html -new file mode 100644 -index 0000000..5802f2d ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.html -@@ -0,0 +1,11 @@ -+<p>Just a <a href="/url/">URL</a>.</p> -+ -+<p><a href="/url/" title="title">URL and title</a>.</p> -+ -+<p><a href="/url/" title="title preceded by two spaces">URL and title</a>.</p> -+ -+<p><a href="/url/" title="title preceded by a tab">URL and title</a>.</p> -+ -+<p><a href="/url/" title="title has spaces afterward">URL and title</a>.</p> -+ -+<p>[Empty]().</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text -new file mode 100644 -index 0000000..09017a9 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, inline style.text -@@ -0,0 +1,12 @@ -+Just a [URL](/url/). -+ -+[URL and title](/url/ "title"). -+ -+[URL and title](/url/ "title preceded by two spaces"). -+ -+[URL and title](/url/ "title preceded by a tab"). -+ -+[URL and title](/url/ "title has spaces afterward" ). -+ -+ -+[Empty](). -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html -new file mode 100644 -index 0000000..bebefde ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.html -@@ -0,0 +1,52 @@ -+<p>Foo <a href="/url/" title="Title">bar</a>.</p> -+ -+<p>Foo <a href="/url/" title="Title">bar</a>.</p> -+ -+<p>Foo <a href="/url/" title="Title">bar</a>.</p> -+ -+<p>With <a href="/url/">embedded [brackets]</a>.</p> -+ -+<p>Indented <a href="/url">once</a>.</p> -+ -+<p>Indented <a href="/url">twice</a>.</p> -+ -+<p>Indented <a href="/url">thrice</a>.</p> -+ -+<p>Indented [four][] times.</p> -+ -+<pre><code>[four]: /url -+</code></pre> -+ -+<hr> -+ -+<p><a href="foo">this</a> should work</p> -+ -+<p>So should <a href="foo">this</a>.</p> -+ -+<p>And <a href="foo">this</a>.</p> -+ -+<p>And <a href="foo">this</a>.</p> -+ -+<p>And <a href="foo">this</a>.</p> -+ -+<p>But not [that] [].</p> -+ -+<p>Nor [that][].</p> -+ -+<p>Nor [that].</p> -+ -+<p>[Something in brackets like <a href="foo">this</a> should work]</p> -+ -+<p>[Same with <a href="foo">this</a>.]</p> -+ -+<p>In this case, <a href="/somethingelse/">this</a> points to something else.</p> -+ -+<p>Backslashing should suppress [this] and [this].</p> -+ -+<hr> -+ -+<p>Here's one where the <a href="/url/">link -+breaks</a> across lines.</p> -+ -+<p>Here's another where the <a href="/url/">link -+breaks</a> across lines, but with a line-ending space.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text -new file mode 100644 -index 0000000..341ec88 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, reference style.text -@@ -0,0 +1,71 @@ -+Foo [bar] [1]. -+ -+Foo [bar][1]. -+ -+Foo [bar] -+[1]. -+ -+[1]: /url/ "Title" -+ -+ -+With [embedded [brackets]] [b]. -+ -+ -+Indented [once][]. -+ -+Indented [twice][]. -+ -+Indented [thrice][]. -+ -+Indented [four][] times. -+ -+ [once]: /url -+ -+ [twice]: /url -+ -+ [thrice]: /url -+ -+ [four]: /url -+ -+ -+[b]: /url/ -+ -+* * * -+ -+[this] [this] should work -+ -+So should [this][this]. -+ -+And [this] []. -+ -+And [this][]. -+ -+And [this]. -+ -+But not [that] []. -+ -+Nor [that][]. -+ -+Nor [that]. -+ -+[Something in brackets like [this][] should work] -+ -+[Same with [this].] -+ -+In this case, [this](/somethingelse/) points to something else. -+ -+Backslashing should suppress \[this] and [this\]. -+ -+[this]: foo -+ -+ -+* * * -+ -+Here's one where the [link -+breaks] across lines. -+ -+Here's another where the [link -+breaks] across lines, but with a line-ending space. -+ -+ -+[link breaks]: /url/ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html -new file mode 100644 -index 0000000..0b5e1d6 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.html -@@ -0,0 +1,9 @@ -+<p>This is the <a href="/simple">simple case</a>.</p> -+ -+<p>This one has a <a href="/foo">line -+break</a>.</p> -+ -+<p>This one has a <a href="/foo">line -+break</a> with a line-ending space.</p> -+ -+<p><a href="/that">this</a> and the <a href="/other">other</a></p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text -new file mode 100644 -index 0000000..8c44c98 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Links, shortcut references.text -@@ -0,0 +1,20 @@ -+This is the [simple case]. -+ -+[simple case]: /simple -+ -+ -+ -+This one has a [line -+break]. -+ -+This one has a [line -+break] with a line-ending space. -+ -+[line break]: /foo -+ -+ -+[this] [that] and the [other] -+ -+[this]: /this -+[that]: /that -+[other]: /other -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html -new file mode 100644 -index 0000000..611c1ac ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.html -@@ -0,0 +1,3 @@ -+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p> -+ -+<p>Foo <a href="/url/" title="Title with "quotes" inside">bar</a>.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text -new file mode 100644 -index 0000000..29d0e42 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Literal quotes in titles.text -@@ -0,0 +1,7 @@ -+Foo [bar][]. -+ -+Foo [bar](/url/ "Title with "quotes" inside"). -+ -+ -+ [bar]: /url/ "Title with "quotes" inside" -+ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html -new file mode 100644 -index 0000000..ea3a61c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.html -@@ -0,0 +1,314 @@ -+<h1>Markdown: Basics</h1> -+ -+<ul id="ProjectSubmenu"> -+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> -+ <li><a class="selected" title="Markdown Basics">Basics</a></li> -+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li> -+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> -+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> -+</ul> -+ -+<h2>Getting the Gist of Markdown's Formatting Syntax</h2> -+ -+<p>This page offers a brief overview of what it's like to use Markdown. -+The <a href="/projects/markdown/syntax" title="Markdown Syntax">syntax page</a> provides complete, detailed documentation for -+every feature, but Markdown should be very easy to pick up simply by -+looking at a few examples of it in action. The examples on this page -+are written in a before/after style, showing example syntax and the -+HTML output produced by Markdown.</p> -+ -+<p>It's also helpful to simply try Markdown out; the <a href="/projects/markdown/dingus" title="Markdown Dingus">Dingus</a> is a -+web application that allows you type your own Markdown-formatted text -+and translate it to XHTML.</p> -+ -+<p><strong>Note:</strong> This document is itself written using Markdown; you -+can <a href="/projects/markdown/basics.text">see the source for it by adding '.text' to the URL</a>.</p> -+ -+<h2>Paragraphs, Headers, Blockquotes</h2> -+ -+<p>A paragraph is simply one or more consecutive lines of text, separated -+by one or more blank lines. (A blank line is any line that looks like a -+blank line -- a line containing nothing spaces or tabs is considered -+blank.) Normal paragraphs should not be intended with spaces or tabs.</p> -+ -+<p>Markdown offers two styles of headers: <em>Setext</em> and <em>atx</em>. -+Setext-style headers for <code><h1></code> and <code><h2></code> are created by -+"underlining" with equal signs (<code>=</code>) and hyphens (<code>-</code>), respectively. -+To create an atx-style header, you put 1-6 hash marks (<code>#</code>) at the -+beginning of the line -- the number of hashes equals the resulting -+HTML header level.</p> -+ -+<p>Blockquotes are indicated using email-style '<code>></code>' angle brackets.</p> -+ -+<p>Markdown:</p> -+ -+<pre><code>A First Level Header -+==================== -+ -+A Second Level Header -+--------------------- -+ -+Now is the time for all good men to come to -+the aid of their country. This is just a -+regular paragraph. -+ -+The quick brown fox jumped over the lazy -+dog's back. -+ -+### Header 3 -+ -+> This is a blockquote. -+> -+> This is the second paragraph in the blockquote. -+> -+> ## This is an H2 in a blockquote -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><h1>A First Level Header</h1> -+ -+<h2>A Second Level Header</h2> -+ -+<p>Now is the time for all good men to come to -+the aid of their country. This is just a -+regular paragraph.</p> -+ -+<p>The quick brown fox jumped over the lazy -+dog's back.</p> -+ -+<h3>Header 3</h3> -+ -+<blockquote> -+ <p>This is a blockquote.</p> -+ -+ <p>This is the second paragraph in the blockquote.</p> -+ -+ <h2>This is an H2 in a blockquote</h2> -+</blockquote> -+</code></pre> -+ -+<h3>Phrase Emphasis</h3> -+ -+<p>Markdown uses asterisks and underscores to indicate spans of emphasis.</p> -+ -+<p>Markdown:</p> -+ -+<pre><code>Some of these words *are emphasized*. -+Some of these words _are emphasized also_. -+ -+Use two asterisks for **strong emphasis**. -+Or, if you prefer, __use two underscores instead__. -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>Some of these words <em>are emphasized</em>. -+Some of these words <em>are emphasized also</em>.</p> -+ -+<p>Use two asterisks for <strong>strong emphasis</strong>. -+Or, if you prefer, <strong>use two underscores instead</strong>.</p> -+</code></pre> -+ -+<h2>Lists</h2> -+ -+<p>Unordered (bulleted) lists use asterisks, pluses, and hyphens (<code>*</code>, -+<code>+</code>, and <code>-</code>) as list markers. These three markers are -+interchangable; this:</p> -+ -+<pre><code>* Candy. -+* Gum. -+* Booze. -+</code></pre> -+ -+<p>this:</p> -+ -+<pre><code>+ Candy. -++ Gum. -++ Booze. -+</code></pre> -+ -+<p>and this:</p> -+ -+<pre><code>- Candy. -+- Gum. -+- Booze. -+</code></pre> -+ -+<p>all produce the same output:</p> -+ -+<pre><code><ul> -+<li>Candy.</li> -+<li>Gum.</li> -+<li>Booze.</li> -+</ul> -+</code></pre> -+ -+<p>Ordered (numbered) lists use regular numbers, followed by periods, as -+list markers:</p> -+ -+<pre><code>1. Red -+2. Green -+3. Blue -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><ol> -+<li>Red</li> -+<li>Green</li> -+<li>Blue</li> -+</ol> -+</code></pre> -+ -+<p>If you put blank lines between items, you'll get <code><p></code> tags for the -+list item text. You can create multi-paragraph list items by indenting -+the paragraphs by 4 spaces or 1 tab:</p> -+ -+<pre><code>* A list item. -+ -+ With multiple paragraphs. -+ -+* Another item in the list. -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><ul> -+<li><p>A list item.</p> -+<p>With multiple paragraphs.</p></li> -+<li><p>Another item in the list.</p></li> -+</ul> -+</code></pre> -+ -+<h3>Links</h3> -+ -+<p>Markdown supports two styles for creating links: <em>inline</em> and -+<em>reference</em>. With both styles, you use square brackets to delimit the -+text you want to turn into a link.</p> -+ -+<p>Inline-style links use parentheses immediately after the link text. -+For example:</p> -+ -+<pre><code>This is an [example link](http://example.com/). -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>This is an <a href="http://example.com/"> -+example link</a>.</p> -+</code></pre> -+ -+<p>Optionally, you may include a title attribute in the parentheses:</p> -+ -+<pre><code>This is an [example link](http://example.com/ "With a Title"). -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>This is an <a href="http://example.com/" title="With a Title"> -+example link</a>.</p> -+</code></pre> -+ -+<p>Reference-style links allow you to refer to your links by names, which -+you define elsewhere in your document:</p> -+ -+<pre><code>I get 10 times more traffic from [Google][1] than from -+[Yahoo][2] or [MSN][3]. -+ -+[1]: http://google.com/ "Google" -+[2]: http://search.yahoo.com/ "Yahoo Search" -+[3]: http://search.msn.com/ "MSN Search" -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>I get 10 times more traffic from <a href="http://google.com/" -+title="Google">Google</a> than from <a href="http://search.yahoo.com/" -+title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" -+title="MSN Search">MSN</a>.</p> -+</code></pre> -+ -+<p>The title attribute is optional. Link names may contain letters, -+numbers and spaces, but are <em>not</em> case sensitive:</p> -+ -+<pre><code>I start my morning with a cup of coffee and -+[The New York Times][NY Times]. -+ -+[ny times]: http://www.nytimes.com/ -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>I start my morning with a cup of coffee and -+<a href="http://www.nytimes.com/">The New York Times</a>.</p> -+</code></pre> -+ -+<h3>Images</h3> -+ -+<p>Image syntax is very much like link syntax.</p> -+ -+<p>Inline (titles are optional):</p> -+ -+<pre><code> -+</code></pre> -+ -+<p>Reference-style:</p> -+ -+<pre><code>![alt text][id] -+ -+[id]: /path/to/img.jpg "Title" -+</code></pre> -+ -+<p>Both of the above examples produce the same output:</p> -+ -+<pre><code><img src="/path/to/img.jpg" alt="alt text" title="Title" /> -+</code></pre> -+ -+<h3>Code</h3> -+ -+<p>In a regular paragraph, you can create code span by wrapping text in -+backtick quotes. Any ampersands (<code>&</code>) and angle brackets (<code><</code> or -+<code>></code>) will automatically be translated into HTML entities. This makes -+it easy to use Markdown to write about HTML example code:</p> -+ -+<pre><code>I strongly recommend against using any `<blink>` tags. -+ -+I wish SmartyPants used named entities like `&mdash;` -+instead of decimal-encoded entites like `&#8212;`. -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>I strongly recommend against using any -+<code>&lt;blink&gt;</code> tags.</p> -+ -+<p>I wish SmartyPants used named entities like -+<code>&amp;mdash;</code> instead of decimal-encoded -+entites like <code>&amp;#8212;</code>.</p> -+</code></pre> -+ -+<p>To specify an entire block of pre-formatted code, indent every line of -+the block by 4 spaces or 1 tab. Just like with code spans, <code>&</code>, <code><</code>, -+and <code>></code> characters will be escaped automatically.</p> -+ -+<p>Markdown:</p> -+ -+<pre><code>If you want your page to validate under XHTML 1.0 Strict, -+you've got to put paragraph tags in your blockquotes: -+ -+ <blockquote> -+ <p>For example.</p> -+ </blockquote> -+</code></pre> -+ -+<p>Output:</p> -+ -+<pre><code><p>If you want your page to validate under XHTML 1.0 Strict, -+you've got to put paragraph tags in your blockquotes:</p> -+ -+<pre><code>&lt;blockquote&gt; -+ &lt;p&gt;For example.&lt;/p&gt; -+&lt;/blockquote&gt; -+</code></pre> -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text -new file mode 100644 -index 0000000..486055c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Basics.text -@@ -0,0 +1,306 @@ -+Markdown: Basics -+================ -+ -+<ul id="ProjectSubmenu"> -+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> -+ <li><a class="selected" title="Markdown Basics">Basics</a></li> -+ <li><a href="/projects/markdown/syntax" title="Markdown Syntax Documentation">Syntax</a></li> -+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> -+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> -+</ul> -+ -+ -+Getting the Gist of Markdown's Formatting Syntax -+------------------------------------------------ -+ -+This page offers a brief overview of what it's like to use Markdown. -+The [syntax page] [s] provides complete, detailed documentation for -+every feature, but Markdown should be very easy to pick up simply by -+looking at a few examples of it in action. The examples on this page -+are written in a before/after style, showing example syntax and the -+HTML output produced by Markdown. -+ -+It's also helpful to simply try Markdown out; the [Dingus] [d] is a -+web application that allows you type your own Markdown-formatted text -+and translate it to XHTML. -+ -+**Note:** This document is itself written using Markdown; you -+can [see the source for it by adding '.text' to the URL] [src]. -+ -+ [s]: /projects/markdown/syntax "Markdown Syntax" -+ [d]: /projects/markdown/dingus "Markdown Dingus" -+ [src]: /projects/markdown/basics.text -+ -+ -+## Paragraphs, Headers, Blockquotes ## -+ -+A paragraph is simply one or more consecutive lines of text, separated -+by one or more blank lines. (A blank line is any line that looks like a -+blank line -- a line containing nothing spaces or tabs is considered -+blank.) Normal paragraphs should not be intended with spaces or tabs. -+ -+Markdown offers two styles of headers: *Setext* and *atx*. -+Setext-style headers for `<h1>` and `<h2>` are created by -+"underlining" with equal signs (`=`) and hyphens (`-`), respectively. -+To create an atx-style header, you put 1-6 hash marks (`#`) at the -+beginning of the line -- the number of hashes equals the resulting -+HTML header level. -+ -+Blockquotes are indicated using email-style '`>`' angle brackets. -+ -+Markdown: -+ -+ A First Level Header -+ ==================== -+ -+ A Second Level Header -+ --------------------- -+ -+ Now is the time for all good men to come to -+ the aid of their country. This is just a -+ regular paragraph. -+ -+ The quick brown fox jumped over the lazy -+ dog's back. -+ -+ ### Header 3 -+ -+ > This is a blockquote. -+ > -+ > This is the second paragraph in the blockquote. -+ > -+ > ## This is an H2 in a blockquote -+ -+ -+Output: -+ -+ <h1>A First Level Header</h1> -+ -+ <h2>A Second Level Header</h2> -+ -+ <p>Now is the time for all good men to come to -+ the aid of their country. This is just a -+ regular paragraph.</p> -+ -+ <p>The quick brown fox jumped over the lazy -+ dog's back.</p> -+ -+ <h3>Header 3</h3> -+ -+ <blockquote> -+ <p>This is a blockquote.</p> -+ -+ <p>This is the second paragraph in the blockquote.</p> -+ -+ <h2>This is an H2 in a blockquote</h2> -+ </blockquote> -+ -+ -+ -+### Phrase Emphasis ### -+ -+Markdown uses asterisks and underscores to indicate spans of emphasis. -+ -+Markdown: -+ -+ Some of these words *are emphasized*. -+ Some of these words _are emphasized also_. -+ -+ Use two asterisks for **strong emphasis**. -+ Or, if you prefer, __use two underscores instead__. -+ -+Output: -+ -+ <p>Some of these words <em>are emphasized</em>. -+ Some of these words <em>are emphasized also</em>.</p> -+ -+ <p>Use two asterisks for <strong>strong emphasis</strong>. -+ Or, if you prefer, <strong>use two underscores instead</strong>.</p> -+ -+ -+ -+## Lists ## -+ -+Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, -+`+`, and `-`) as list markers. These three markers are -+interchangable; this: -+ -+ * Candy. -+ * Gum. -+ * Booze. -+ -+this: -+ -+ + Candy. -+ + Gum. -+ + Booze. -+ -+and this: -+ -+ - Candy. -+ - Gum. -+ - Booze. -+ -+all produce the same output: -+ -+ <ul> -+ <li>Candy.</li> -+ <li>Gum.</li> -+ <li>Booze.</li> -+ </ul> -+ -+Ordered (numbered) lists use regular numbers, followed by periods, as -+list markers: -+ -+ 1. Red -+ 2. Green -+ 3. Blue -+ -+Output: -+ -+ <ol> -+ <li>Red</li> -+ <li>Green</li> -+ <li>Blue</li> -+ </ol> -+ -+If you put blank lines between items, you'll get `<p>` tags for the -+list item text. You can create multi-paragraph list items by indenting -+the paragraphs by 4 spaces or 1 tab: -+ -+ * A list item. -+ -+ With multiple paragraphs. -+ -+ * Another item in the list. -+ -+Output: -+ -+ <ul> -+ <li><p>A list item.</p> -+ <p>With multiple paragraphs.</p></li> -+ <li><p>Another item in the list.</p></li> -+ </ul> -+ -+ -+ -+### Links ### -+ -+Markdown supports two styles for creating links: *inline* and -+*reference*. With both styles, you use square brackets to delimit the -+text you want to turn into a link. -+ -+Inline-style links use parentheses immediately after the link text. -+For example: -+ -+ This is an [example link](http://example.com/). -+ -+Output: -+ -+ <p>This is an <a href="http://example.com/"> -+ example link</a>.</p> -+ -+Optionally, you may include a title attribute in the parentheses: -+ -+ This is an [example link](http://example.com/ "With a Title"). -+ -+Output: -+ -+ <p>This is an <a href="http://example.com/" title="With a Title"> -+ example link</a>.</p> -+ -+Reference-style links allow you to refer to your links by names, which -+you define elsewhere in your document: -+ -+ I get 10 times more traffic from [Google][1] than from -+ [Yahoo][2] or [MSN][3]. -+ -+ [1]: http://google.com/ "Google" -+ [2]: http://search.yahoo.com/ "Yahoo Search" -+ [3]: http://search.msn.com/ "MSN Search" -+ -+Output: -+ -+ <p>I get 10 times more traffic from <a href="http://google.com/" -+ title="Google">Google</a> than from <a href="http://search.yahoo.com/" -+ title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/" -+ title="MSN Search">MSN</a>.</p> -+ -+The title attribute is optional. Link names may contain letters, -+numbers and spaces, but are *not* case sensitive: -+ -+ I start my morning with a cup of coffee and -+ [The New York Times][NY Times]. -+ -+ [ny times]: http://www.nytimes.com/ -+ -+Output: -+ -+ <p>I start my morning with a cup of coffee and -+ <a href="http://www.nytimes.com/">The New York Times</a>.</p> -+ -+ -+### Images ### -+ -+Image syntax is very much like link syntax. -+ -+Inline (titles are optional): -+ -+  -+ -+Reference-style: -+ -+ ![alt text][id] -+ -+ [id]: /path/to/img.jpg "Title" -+ -+Both of the above examples produce the same output: -+ -+ <img src="/path/to/img.jpg" alt="alt text" title="Title" /> -+ -+ -+ -+### Code ### -+ -+In a regular paragraph, you can create code span by wrapping text in -+backtick quotes. Any ampersands (`&`) and angle brackets (`<` or -+`>`) will automatically be translated into HTML entities. This makes -+it easy to use Markdown to write about HTML example code: -+ -+ I strongly recommend against using any `<blink>` tags. -+ -+ I wish SmartyPants used named entities like `—` -+ instead of decimal-encoded entites like `—`. -+ -+Output: -+ -+ <p>I strongly recommend against using any -+ <code><blink></code> tags.</p> -+ -+ <p>I wish SmartyPants used named entities like -+ <code>&mdash;</code> instead of decimal-encoded -+ entites like <code>&#8212;</code>.</p> -+ -+ -+To specify an entire block of pre-formatted code, indent every line of -+the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`, -+and `>` characters will be escaped automatically. -+ -+Markdown: -+ -+ If you want your page to validate under XHTML 1.0 Strict, -+ you've got to put paragraph tags in your blockquotes: -+ -+ <blockquote> -+ <p>For example.</p> -+ </blockquote> -+ -+Output: -+ -+ <p>If you want your page to validate under XHTML 1.0 Strict, -+ you've got to put paragraph tags in your blockquotes:</p> -+ -+ <pre><code><blockquote> -+ <p>For example.</p> -+ </blockquote> -+ </code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html -new file mode 100644 -index 0000000..61dde59 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.html -@@ -0,0 +1,946 @@ -+<h1>Markdown: Syntax</h1> -+ -+<ul id="ProjectSubmenu"> -+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> -+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li> -+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li> -+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> -+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> -+</ul> -+ -+<ul> -+<li><a href="#overview">Overview</a> -+ -+<ul> -+<li><a href="#philosophy">Philosophy</a></li> -+<li><a href="#html">Inline HTML</a></li> -+<li><a href="#autoescape">Automatic Escaping for Special Characters</a></li> -+</ul></li> -+<li><a href="#block">Block Elements</a> -+ -+<ul> -+<li><a href="#p">Paragraphs and Line Breaks</a></li> -+<li><a href="#header">Headers</a></li> -+<li><a href="#blockquote">Blockquotes</a></li> -+<li><a href="#list">Lists</a></li> -+<li><a href="#precode">Code Blocks</a></li> -+<li><a href="#hr">Horizontal Rules</a></li> -+</ul></li> -+<li><a href="#span">Span Elements</a> -+ -+<ul> -+<li><a href="#link">Links</a></li> -+<li><a href="#em">Emphasis</a></li> -+<li><a href="#code">Code</a></li> -+<li><a href="#img">Images</a></li> -+</ul></li> -+<li><a href="#misc">Miscellaneous</a> -+ -+<ul> -+<li><a href="#backslash">Backslash Escapes</a></li> -+<li><a href="#autolink">Automatic Links</a></li> -+</ul></li> -+</ul> -+ -+<p><strong>Note:</strong> This document is itself written using Markdown; you -+can <a href="/projects/markdown/syntax.text">see the source for it by adding '.text' to the URL</a>.</p> -+ -+<hr> -+ -+<h2 id="overview">Overview</h2> -+ -+<h3 id="philosophy">Philosophy</h3> -+ -+<p>Markdown is intended to be as easy-to-read and easy-to-write as is feasible.</p> -+ -+<p>Readability, however, is emphasized above all else. A Markdown-formatted -+document should be publishable as-is, as plain text, without looking -+like it's been marked up with tags or formatting instructions. While -+Markdown's syntax has been influenced by several existing text-to-HTML -+filters -- including <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a>, <a href="http://www.aaronsw.com/2002/atx/">atx</a>, <a href="http://textism.com/tools/textile/">Textile</a>, <a href="http://docutils.sourceforge.net/rst.html">reStructuredText</a>, -+<a href="http://www.triptico.com/software/grutatxt.html">Grutatext</a>, and <a href="http://ettext.taint.org/doc/">EtText</a> -- the single biggest source of -+inspiration for Markdown's syntax is the format of plain text email.</p> -+ -+<p>To this end, Markdown's syntax is comprised entirely of punctuation -+characters, which punctuation characters have been carefully chosen so -+as to look like what they mean. E.g., asterisks around a word actually -+look like *emphasis*. Markdown lists look like, well, lists. Even -+blockquotes look like quoted passages of text, assuming you've ever -+used email.</p> -+ -+<h3 id="html">Inline HTML</h3> -+ -+<p>Markdown's syntax is intended for one purpose: to be used as a -+format for <em>writing</em> for the web.</p> -+ -+<p>Markdown is not a replacement for HTML, or even close to it. Its -+syntax is very small, corresponding only to a very small subset of -+HTML tags. The idea is <em>not</em> to create a syntax that makes it easier -+to insert HTML tags. In my opinion, HTML tags are already easy to -+insert. The idea for Markdown is to make it easy to read, write, and -+edit prose. HTML is a <em>publishing</em> format; Markdown is a <em>writing</em> -+format. Thus, Markdown's formatting syntax only addresses issues that -+can be conveyed in plain text.</p> -+ -+<p>For any markup that is not covered by Markdown's syntax, you simply -+use HTML itself. There's no need to preface it or delimit it to -+indicate that you're switching from Markdown to HTML; you just use -+the tags.</p> -+ -+<p>The only restrictions are that block-level HTML elements -- e.g. <code><div></code>, -+<code><table></code>, <code><pre></code>, <code><p></code>, etc. -- must be separated from surrounding -+content by blank lines, and the start and end tags of the block should -+not be indented with tabs or spaces. Markdown is smart enough not -+to add extra (unwanted) <code><p></code> tags around HTML block-level tags.</p> -+ -+<p>For example, to add an HTML table to a Markdown article:</p> -+ -+<pre><code>This is a regular paragraph. -+ -+<table> -+ <tr> -+ <td>Foo</td> -+ </tr> -+</table> -+ -+This is another regular paragraph. -+</code></pre> -+ -+<p>Note that Markdown formatting syntax is not processed within block-level -+HTML tags. E.g., you can't use Markdown-style <code>*emphasis*</code> inside an -+HTML block.</p> -+ -+<p>Span-level HTML tags -- e.g. <code><span></code>, <code><cite></code>, or <code><del></code> -- can be -+used anywhere in a Markdown paragraph, list item, or header. If you -+want, you can even use HTML tags instead of Markdown formatting; e.g. if -+you'd prefer to use HTML <code><a></code> or <code><img></code> tags instead of Markdown's -+link or image syntax, go right ahead.</p> -+ -+<p>Unlike block-level HTML tags, Markdown syntax <em>is</em> processed within -+span-level tags.</p> -+ -+<h3 id="autoescape">Automatic Escaping for Special Characters</h3> -+ -+<p>In HTML, there are two characters that demand special treatment: <code><</code> -+and <code>&</code>. Left angle brackets are used to start tags; ampersands are -+used to denote HTML entities. If you want to use them as literal -+characters, you must escape them as entities, e.g. <code>&lt;</code>, and -+<code>&amp;</code>.</p> -+ -+<p>Ampersands in particular are bedeviling for web writers. If you want to -+write about 'AT&T', you need to write '<code>AT&amp;T</code>'. You even need to -+escape ampersands within URLs. Thus, if you want to link to:</p> -+ -+<pre><code>http://images.google.com/images?num=30&q=larry+bird -+</code></pre> -+ -+<p>you need to encode the URL as:</p> -+ -+<pre><code>http://images.google.com/images?num=30&amp;q=larry+bird -+</code></pre> -+ -+<p>in your anchor tag <code>href</code> attribute. Needless to say, this is easy to -+forget, and is probably the single most common source of HTML validation -+errors in otherwise well-marked-up web sites.</p> -+ -+<p>Markdown allows you to use these characters naturally, taking care of -+all the necessary escaping for you. If you use an ampersand as part of -+an HTML entity, it remains unchanged; otherwise it will be translated -+into <code>&amp;</code>.</p> -+ -+<p>So, if you want to include a copyright symbol in your article, you can write:</p> -+ -+<pre><code>&copy; -+</code></pre> -+ -+<p>and Markdown will leave it alone. But if you write:</p> -+ -+<pre><code>AT&T -+</code></pre> -+ -+<p>Markdown will translate it to:</p> -+ -+<pre><code>AT&amp;T -+</code></pre> -+ -+<p>Similarly, because Markdown supports <a href="#html">inline HTML</a>, if you use -+angle brackets as delimiters for HTML tags, Markdown will treat them as -+such. But if you write:</p> -+ -+<pre><code>4 < 5 -+</code></pre> -+ -+<p>Markdown will translate it to:</p> -+ -+<pre><code>4 &lt; 5 -+</code></pre> -+ -+<p>However, inside Markdown code spans and blocks, angle brackets and -+ampersands are <em>always</em> encoded automatically. This makes it easy to use -+Markdown to write about HTML code. (As opposed to raw HTML, which is a -+terrible format for writing about HTML syntax, because every single <code><</code> -+and <code>&</code> in your example code needs to be escaped.)</p> -+ -+<hr> -+ -+<h2 id="block">Block Elements</h2> -+ -+<h3 id="p">Paragraphs and Line Breaks</h3> -+ -+<p>A paragraph is simply one or more consecutive lines of text, separated -+by one or more blank lines. (A blank line is any line that looks like a -+blank line -- a line containing nothing but spaces or tabs is considered -+blank.) Normal paragraphs should not be intended with spaces or tabs.</p> -+ -+<p>The implication of the "one or more consecutive lines of text" rule is -+that Markdown supports "hard-wrapped" text paragraphs. This differs -+significantly from most other text-to-HTML formatters (including Movable -+Type's "Convert Line Breaks" option) which translate every line break -+character in a paragraph into a <code><br /></code> tag.</p> -+ -+<p>When you <em>do</em> want to insert a <code><br /></code> break tag using Markdown, you -+end a line with two or more spaces, then type return.</p> -+ -+<p>Yes, this takes a tad more effort to create a <code><br /></code>, but a simplistic -+"every line break is a <code><br /></code>" rule wouldn't work for Markdown. -+Markdown's email-style <a href="#blockquote">blockquoting</a> and multi-paragraph <a href="#list">list items</a> -+work best -- and look better -- when you format them with hard breaks.</p> -+ -+<h3 id="header">Headers</h3> -+ -+<p>Markdown supports two styles of headers, <a href="http://docutils.sourceforge.net/mirror/setext.html">Setext</a> and <a href="http://www.aaronsw.com/2002/atx/">atx</a>.</p> -+ -+<p>Setext-style headers are "underlined" using equal signs (for first-level -+headers) and dashes (for second-level headers). For example:</p> -+ -+<pre><code>This is an H1 -+============= -+ -+This is an H2 -+------------- -+</code></pre> -+ -+<p>Any number of underlining <code>=</code>'s or <code>-</code>'s will work.</p> -+ -+<p>Atx-style headers use 1-6 hash characters at the start of the line, -+corresponding to header levels 1-6. For example:</p> -+ -+<pre><code># This is an H1 -+ -+## This is an H2 -+ -+###### This is an H6 -+</code></pre> -+ -+<p>Optionally, you may "close" atx-style headers. This is purely -+cosmetic -- you can use this if you think it looks better. The -+closing hashes don't even need to match the number of hashes -+used to open the header. (The number of opening hashes -+determines the header level.) :</p> -+ -+<pre><code># This is an H1 # -+ -+## This is an H2 ## -+ -+### This is an H3 ###### -+</code></pre> -+ -+<h3 id="blockquote">Blockquotes</h3> -+ -+<p>Markdown uses email-style <code>></code> characters for blockquoting. If you're -+familiar with quoting passages of text in an email message, then you -+know how to create a blockquote in Markdown. It looks best if you hard -+wrap the text and put a <code>></code> before every line:</p> -+ -+<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, -+> consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. -+> Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. -+> -+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse -+> id sem consectetuer libero luctus adipiscing. -+</code></pre> -+ -+<p>Markdown allows you to be lazy and only put the <code>></code> before the first -+line of a hard-wrapped paragraph:</p> -+ -+<pre><code>> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, -+consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. -+Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. -+ -+> Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse -+id sem consectetuer libero luctus adipiscing. -+</code></pre> -+ -+<p>Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by -+adding additional levels of <code>></code>:</p> -+ -+<pre><code>> This is the first level of quoting. -+> -+> > This is nested blockquote. -+> -+> Back to the first level. -+</code></pre> -+ -+<p>Blockquotes can contain other Markdown elements, including headers, lists, -+and code blocks:</p> -+ -+<pre><code>> ## This is a header. -+> -+> 1. This is the first list item. -+> 2. This is the second list item. -+> -+> Here's some example code: -+> -+> return shell_exec("echo $input | $markdown_script"); -+</code></pre> -+ -+<p>Any decent text editor should make email-style quoting easy. For -+example, with BBEdit, you can make a selection and choose Increase -+Quote Level from the Text menu.</p> -+ -+<h3 id="list">Lists</h3> -+ -+<p>Markdown supports ordered (numbered) and unordered (bulleted) lists.</p> -+ -+<p>Unordered lists use asterisks, pluses, and hyphens -- interchangably -+-- as list markers:</p> -+ -+<pre><code>* Red -+* Green -+* Blue -+</code></pre> -+ -+<p>is equivalent to:</p> -+ -+<pre><code>+ Red -++ Green -++ Blue -+</code></pre> -+ -+<p>and:</p> -+ -+<pre><code>- Red -+- Green -+- Blue -+</code></pre> -+ -+<p>Ordered lists use numbers followed by periods:</p> -+ -+<pre><code>1. Bird -+2. McHale -+3. Parish -+</code></pre> -+ -+<p>It's important to note that the actual numbers you use to mark the -+list have no effect on the HTML output Markdown produces. The HTML -+Markdown produces from the above list is:</p> -+ -+<pre><code><ol> -+<li>Bird</li> -+<li>McHale</li> -+<li>Parish</li> -+</ol> -+</code></pre> -+ -+<p>If you instead wrote the list in Markdown like this:</p> -+ -+<pre><code>1. Bird -+1. McHale -+1. Parish -+</code></pre> -+ -+<p>or even:</p> -+ -+<pre><code>3. Bird -+1. McHale -+8. Parish -+</code></pre> -+ -+<p>you'd get the exact same HTML output. The point is, if you want to, -+you can use ordinal numbers in your ordered Markdown lists, so that -+the numbers in your source match the numbers in your published HTML. -+But if you want to be lazy, you don't have to.</p> -+ -+<p>If you do use lazy list numbering, however, you should still start the -+list with the number 1. At some point in the future, Markdown may support -+starting ordered lists at an arbitrary number.</p> -+ -+<p>List markers typically start at the left margin, but may be indented by -+up to three spaces. List markers must be followed by one or more spaces -+or a tab.</p> -+ -+<p>To make lists look nice, you can wrap items with hanging indents:</p> -+ -+<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. -+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, -+ viverra nec, fringilla in, laoreet vitae, risus. -+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. -+ Suspendisse id sem consectetuer libero luctus adipiscing. -+</code></pre> -+ -+<p>But if you want to be lazy, you don't have to:</p> -+ -+<pre><code>* Lorem ipsum dolor sit amet, consectetuer adipiscing elit. -+Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, -+viverra nec, fringilla in, laoreet vitae, risus. -+* Donec sit amet nisl. Aliquam semper ipsum sit amet velit. -+Suspendisse id sem consectetuer libero luctus adipiscing. -+</code></pre> -+ -+<p>If list items are separated by blank lines, Markdown will wrap the -+items in <code><p></code> tags in the HTML output. For example, this input:</p> -+ -+<pre><code>* Bird -+* Magic -+</code></pre> -+ -+<p>will turn into:</p> -+ -+<pre><code><ul> -+<li>Bird</li> -+<li>Magic</li> -+</ul> -+</code></pre> -+ -+<p>But this:</p> -+ -+<pre><code>* Bird -+ -+* Magic -+</code></pre> -+ -+<p>will turn into:</p> -+ -+<pre><code><ul> -+<li><p>Bird</p></li> -+<li><p>Magic</p></li> -+</ul> -+</code></pre> -+ -+<p>List items may consist of multiple paragraphs. Each subsequent -+paragraph in a list item must be intended by either 4 spaces -+or one tab:</p> -+ -+<pre><code>1. This is a list item with two paragraphs. Lorem ipsum dolor -+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit -+ mi posuere lectus. -+ -+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet -+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum -+ sit amet velit. -+ -+2. Suspendisse id sem consectetuer libero luctus adipiscing. -+</code></pre> -+ -+<p>It looks nice if you indent every line of the subsequent -+paragraphs, but here again, Markdown will allow you to be -+lazy:</p> -+ -+<pre><code>* This is a list item with two paragraphs. -+ -+ This is the second paragraph in the list item. You're -+only required to indent the first line. Lorem ipsum dolor -+sit amet, consectetuer adipiscing elit. -+ -+* Another item in the same list. -+</code></pre> -+ -+<p>To put a blockquote within a list item, the blockquote's <code>></code> -+delimiters need to be indented:</p> -+ -+<pre><code>* A list item with a blockquote: -+ -+ > This is a blockquote -+ > inside a list item. -+</code></pre> -+ -+<p>To put a code block within a list item, the code block needs -+to be indented <em>twice</em> -- 8 spaces or two tabs:</p> -+ -+<pre><code>* A list item with a code block: -+ -+ <code goes here> -+</code></pre> -+ -+<p>It's worth noting that it's possible to trigger an ordered list by -+accident, by writing something like this:</p> -+ -+<pre><code>1986. What a great season. -+</code></pre> -+ -+<p>In other words, a <em>number-period-space</em> sequence at the beginning of a -+line. To avoid this, you can backslash-escape the period:</p> -+ -+<pre><code>1986\. What a great season. -+</code></pre> -+ -+<h3 id="precode">Code Blocks</h3> -+ -+<p>Pre-formatted code blocks are used for writing about programming or -+markup source code. Rather than forming normal paragraphs, the lines -+of a code block are interpreted literally. Markdown wraps a code block -+in both <code><pre></code> and <code><code></code> tags.</p> -+ -+<p>To produce a code block in Markdown, simply indent every line of the -+block by at least 4 spaces or 1 tab. For example, given this input:</p> -+ -+<pre><code>This is a normal paragraph: -+ -+ This is a code block. -+</code></pre> -+ -+<p>Markdown will generate:</p> -+ -+<pre><code><p>This is a normal paragraph:</p> -+ -+<pre><code>This is a code block. -+</code></pre> -+</code></pre> -+ -+<p>One level of indentation -- 4 spaces or 1 tab -- is removed from each -+line of the code block. For example, this:</p> -+ -+<pre><code>Here is an example of AppleScript: -+ -+ tell application "Foo" -+ beep -+ end tell -+</code></pre> -+ -+<p>will turn into:</p> -+ -+<pre><code><p>Here is an example of AppleScript:</p> -+ -+<pre><code>tell application "Foo" -+ beep -+end tell -+</code></pre> -+</code></pre> -+ -+<p>A code block continues until it reaches a line that is not indented -+(or the end of the article).</p> -+ -+<p>Within a code block, ampersands (<code>&</code>) and angle brackets (<code><</code> and <code>></code>) -+are automatically converted into HTML entities. This makes it very -+easy to include example HTML source code using Markdown -- just paste -+it and indent it, and Markdown will handle the hassle of encoding the -+ampersands and angle brackets. For example, this:</p> -+ -+<pre><code> <div class="footer"> -+ &copy; 2004 Foo Corporation -+ </div> -+</code></pre> -+ -+<p>will turn into:</p> -+ -+<pre><code><pre><code>&lt;div class="footer"&gt; -+ &amp;copy; 2004 Foo Corporation -+&lt;/div&gt; -+</code></pre> -+</code></pre> -+ -+<p>Regular Markdown syntax is not processed within code blocks. E.g., -+asterisks are just literal asterisks within a code block. This means -+it's also easy to use Markdown to write about Markdown's own syntax.</p> -+ -+<h3 id="hr">Horizontal Rules</h3> -+ -+<p>You can produce a horizontal rule tag (<code><hr /></code>) by placing three or -+more hyphens, asterisks, or underscores on a line by themselves. If you -+wish, you may use spaces between the hyphens or asterisks. Each of the -+following lines will produce a horizontal rule:</p> -+ -+<pre><code>* * * -+ -+*** -+ -+***** -+ -+- - - -+ -+--------------------------------------- -+ -+_ _ _ -+</code></pre> -+ -+<hr> -+ -+<h2 id="span">Span Elements</h2> -+ -+<h3 id="link">Links</h3> -+ -+<p>Markdown supports two style of links: <em>inline</em> and <em>reference</em>.</p> -+ -+<p>In both styles, the link text is delimited by [square brackets].</p> -+ -+<p>To create an inline link, use a set of regular parentheses immediately -+after the link text's closing square bracket. Inside the parentheses, -+put the URL where you want the link to point, along with an <em>optional</em> -+title for the link, surrounded in quotes. For example:</p> -+ -+<pre><code>This is [an example](http://example.com/ "Title") inline link. -+ -+[This link](http://example.net/) has no title attribute. -+</code></pre> -+ -+<p>Will produce:</p> -+ -+<pre><code><p>This is <a href="http://example.com/" title="Title"> -+an example</a> inline link.</p> -+ -+<p><a href="http://example.net/">This link</a> has no -+title attribute.</p> -+</code></pre> -+ -+<p>If you're referring to a local resource on the same server, you can -+use relative paths:</p> -+ -+<pre><code>See my [About](/about/) page for details. -+</code></pre> -+ -+<p>Reference-style links use a second set of square brackets, inside -+which you place a label of your choosing to identify the link:</p> -+ -+<pre><code>This is [an example][id] reference-style link. -+</code></pre> -+ -+<p>You can optionally use a space to separate the sets of brackets:</p> -+ -+<pre><code>This is [an example] [id] reference-style link. -+</code></pre> -+ -+<p>Then, anywhere in the document, you define your link label like this, -+on a line by itself:</p> -+ -+<pre><code>[id]: http://example.com/ "Optional Title Here" -+</code></pre> -+ -+<p>That is:</p> -+ -+<ul> -+<li>Square brackets containing the link identifier (optionally -+indented from the left margin using up to three spaces);</li> -+<li>followed by a colon;</li> -+<li>followed by one or more spaces (or tabs);</li> -+<li>followed by the URL for the link;</li> -+<li>optionally followed by a title attribute for the link, enclosed -+in double or single quotes.</li> -+</ul> -+ -+<p>The link URL may, optionally, be surrounded by angle brackets:</p> -+ -+<pre><code>[id]: <http://example.com/> "Optional Title Here" -+</code></pre> -+ -+<p>You can put the title attribute on the next line and use extra spaces -+or tabs for padding, which tends to look better with longer URLs:</p> -+ -+<pre><code>[id]: http://example.com/longish/path/to/resource/here -+ "Optional Title Here" -+</code></pre> -+ -+<p>Link definitions are only used for creating links during Markdown -+processing, and are stripped from your document in the HTML output.</p> -+ -+<p>Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are <em>not</em> case sensitive. E.g. these two links:</p> -+ -+<pre><code>[link text][a] -+[link text][A] -+</code></pre> -+ -+<p>are equivalent.</p> -+ -+<p>The <em>implicit link name</em> shortcut allows you to omit the name of the -+link, in which case the link text itself is used as the name. -+Just use an empty set of square brackets -- e.g., to link the word -+"Google" to the google.com web site, you could simply write:</p> -+ -+<pre><code>[Google][] -+</code></pre> -+ -+<p>And then define the link:</p> -+ -+<pre><code>[Google]: http://google.com/ -+</code></pre> -+ -+<p>Because link names may contain spaces, this shortcut even works for -+multiple words in the link text:</p> -+ -+<pre><code>Visit [Daring Fireball][] for more information. -+</code></pre> -+ -+<p>And then define the link:</p> -+ -+<pre><code>[Daring Fireball]: http://daringfireball.net/ -+</code></pre> -+ -+<p>Link definitions can be placed anywhere in your Markdown document. I -+tend to put them immediately after each paragraph in which they're -+used, but if you want, you can put them all at the end of your -+document, sort of like footnotes.</p> -+ -+<p>Here's an example of reference links in action:</p> -+ -+<pre><code>I get 10 times more traffic from [Google] [1] than from -+[Yahoo] [2] or [MSN] [3]. -+ -+ [1]: http://google.com/ "Google" -+ [2]: http://search.yahoo.com/ "Yahoo Search" -+ [3]: http://search.msn.com/ "MSN Search" -+</code></pre> -+ -+<p>Using the implicit link name shortcut, you could instead write:</p> -+ -+<pre><code>I get 10 times more traffic from [Google][] than from -+[Yahoo][] or [MSN][]. -+ -+ [google]: http://google.com/ "Google" -+ [yahoo]: http://search.yahoo.com/ "Yahoo Search" -+ [msn]: http://search.msn.com/ "MSN Search" -+</code></pre> -+ -+<p>Both of the above examples will produce the following HTML output:</p> -+ -+<pre><code><p>I get 10 times more traffic from <a href="http://google.com/" -+title="Google">Google</a> than from -+<a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> -+or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p> -+</code></pre> -+ -+<p>For comparison, here is the same paragraph written using -+Markdown's inline link style:</p> -+ -+<pre><code>I get 10 times more traffic from [Google](http://google.com/ "Google") -+than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or -+[MSN](http://search.msn.com/ "MSN Search"). -+</code></pre> -+ -+<p>The point of reference-style links is not that they're easier to -+write. The point is that with reference-style links, your document -+source is vastly more readable. Compare the above examples: using -+reference-style links, the paragraph itself is only 81 characters -+long; with inline-style links, it's 176 characters; and as raw HTML, -+it's 234 characters. In the raw HTML, there's more markup than there -+is text.</p> -+ -+<p>With Markdown's reference-style links, a source document much more -+closely resembles the final output, as rendered in a browser. By -+allowing you to move the markup-related metadata out of the paragraph, -+you can add links without interrupting the narrative flow of your -+prose.</p> -+ -+<h3 id="em">Emphasis</h3> -+ -+<p>Markdown treats asterisks (<code>*</code>) and underscores (<code>_</code>) as indicators of -+emphasis. Text wrapped with one <code>*</code> or <code>_</code> will be wrapped with an -+HTML <code><em></code> tag; double <code>*</code>'s or <code>_</code>'s will be wrapped with an HTML -+<code><strong></code> tag. E.g., this input:</p> -+ -+<pre><code>*single asterisks* -+ -+_single underscores_ -+ -+**double asterisks** -+ -+__double underscores__ -+</code></pre> -+ -+<p>will produce:</p> -+ -+<pre><code><em>single asterisks</em> -+ -+<em>single underscores</em> -+ -+<strong>double asterisks</strong> -+ -+<strong>double underscores</strong> -+</code></pre> -+ -+<p>You can use whichever style you prefer; the lone restriction is that -+the same character must be used to open and close an emphasis span.</p> -+ -+<p>Emphasis can be used in the middle of a word:</p> -+ -+<pre><code>un*fucking*believable -+</code></pre> -+ -+<p>But if you surround an <code>*</code> or <code>_</code> with spaces, it'll be treated as a -+literal asterisk or underscore.</p> -+ -+<p>To produce a literal asterisk or underscore at a position where it -+would otherwise be used as an emphasis delimiter, you can backslash -+escape it:</p> -+ -+<pre><code>\*this text is surrounded by literal asterisks\* -+</code></pre> -+ -+<h3 id="code">Code</h3> -+ -+<p>To indicate a span of code, wrap it with backtick quotes (<code>`</code>). -+Unlike a pre-formatted code block, a code span indicates code within a -+normal paragraph. For example:</p> -+ -+<pre><code>Use the `printf()` function. -+</code></pre> -+ -+<p>will produce:</p> -+ -+<pre><code><p>Use the <code>printf()</code> function.</p> -+</code></pre> -+ -+<p>To include a literal backtick character within a code span, you can use -+multiple backticks as the opening and closing delimiters:</p> -+ -+<pre><code>``There is a literal backtick (`) here.`` -+</code></pre> -+ -+<p>which will produce this:</p> -+ -+<pre><code><p><code>There is a literal backtick (`) here.</code></p> -+</code></pre> -+ -+<p>The backtick delimiters surrounding a code span may include spaces -- -+one after the opening, one before the closing. This allows you to place -+literal backtick characters at the beginning or end of a code span:</p> -+ -+<pre><code>A single backtick in a code span: `` ` `` -+ -+A backtick-delimited string in a code span: `` `foo` `` -+</code></pre> -+ -+<p>will produce:</p> -+ -+<pre><code><p>A single backtick in a code span: <code>`</code></p> -+ -+<p>A backtick-delimited string in a code span: <code>`foo`</code></p> -+</code></pre> -+ -+<p>With a code span, ampersands and angle brackets are encoded as HTML -+entities automatically, which makes it easy to include example HTML -+tags. Markdown will turn this:</p> -+ -+<pre><code>Please don't use any `<blink>` tags. -+</code></pre> -+ -+<p>into:</p> -+ -+<pre><code><p>Please don't use any <code>&lt;blink&gt;</code> tags.</p> -+</code></pre> -+ -+<p>You can write this:</p> -+ -+<pre><code>`&#8212;` is the decimal-encoded equivalent of `&mdash;`. -+</code></pre> -+ -+<p>to produce:</p> -+ -+<pre><code><p><code>&amp;#8212;</code> is the decimal-encoded -+equivalent of <code>&amp;mdash;</code>.</p> -+</code></pre> -+ -+<h3 id="img">Images</h3> -+ -+<p>Admittedly, it's fairly difficult to devise a "natural" syntax for -+placing images into a plain text document format.</p> -+ -+<p>Markdown uses an image syntax that is intended to resemble the syntax -+for links, allowing for two styles: <em>inline</em> and <em>reference</em>.</p> -+ -+<p>Inline image syntax looks like this:</p> -+ -+<pre><code> -+ -+ -+</code></pre> -+ -+<p>That is:</p> -+ -+<ul> -+<li>An exclamation mark: <code>!</code>;</li> -+<li>followed by a set of square brackets, containing the <code>alt</code> -+attribute text for the image;</li> -+<li>followed by a set of parentheses, containing the URL or path to -+the image, and an optional <code>title</code> attribute enclosed in double -+or single quotes.</li> -+</ul> -+ -+<p>Reference-style image syntax looks like this:</p> -+ -+<pre><code>![Alt text][id] -+</code></pre> -+ -+<p>Where "id" is the name of a defined image reference. Image references -+are defined using syntax identical to link references:</p> -+ -+<pre><code>[id]: url/to/image "Optional title attribute" -+</code></pre> -+ -+<p>As of this writing, Markdown has no syntax for specifying the -+dimensions of an image; if this is important to you, you can simply -+use regular HTML <code><img></code> tags.</p> -+ -+<hr> -+ -+<h2 id="misc">Miscellaneous</h2> -+ -+<h3 id="autolink">Automatic Links</h3> -+ -+<p>Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:</p> -+ -+<pre><code><http://example.com/> -+</code></pre> -+ -+<p>Markdown will turn this into:</p> -+ -+<pre><code><a href="http://example.com/">http://example.com/</a> -+</code></pre> -+ -+<p>Automatic links for email addresses work similarly, except that -+Markdown will also perform a bit of randomized decimal and hex -+entity-encoding to help obscure your address from address-harvesting -+spambots. For example, Markdown will turn this:</p> -+ -+<pre><code><address@example.com> -+</code></pre> -+ -+<p>into something like this:</p> -+ -+<pre><code><a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65; -+&#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111; -+&#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61; -+&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a> -+</code></pre> -+ -+<p>which will render in a browser as a clickable link to "address@example.com".</p> -+ -+<p>(This sort of entity-encoding trick will indeed fool many, if not -+most, address-harvesting bots, but it definitely won't fool all of -+them. It's better than nothing, but an address published in this way -+will probably eventually start receiving spam.)</p> -+ -+<h3 id="backslash">Backslash Escapes</h3> -+ -+<p>Markdown allows you to use backslash escapes to generate literal -+characters which would otherwise have special meaning in Markdown's -+formatting syntax. For example, if you wanted to surround a word with -+literal asterisks (instead of an HTML <code><em></code> tag), you can backslashes -+before the asterisks, like this:</p> -+ -+<pre><code>\*literal asterisks\* -+</code></pre> -+ -+<p>Markdown provides backslash escapes for the following characters:</p> -+ -+<pre><code>\ backslash -+` backtick -+* asterisk -+_ underscore -+{} curly braces -+[] square brackets -+() parentheses -+# hash mark -++ plus sign -+- minus sign (hyphen) -+. dot -+! exclamation mark -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text -new file mode 100644 -index 0000000..57360a1 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Markdown Documentation - Syntax.text -@@ -0,0 +1,888 @@ -+Markdown: Syntax -+================ -+ -+<ul id="ProjectSubmenu"> -+ <li><a href="/projects/markdown/" title="Markdown Project Page">Main</a></li> -+ <li><a href="/projects/markdown/basics" title="Markdown Basics">Basics</a></li> -+ <li><a class="selected" title="Markdown Syntax Documentation">Syntax</a></li> -+ <li><a href="/projects/markdown/license" title="Pricing and License Information">License</a></li> -+ <li><a href="/projects/markdown/dingus" title="Online Markdown Web Form">Dingus</a></li> -+</ul> -+ -+ -+* [Overview](#overview) -+ * [Philosophy](#philosophy) -+ * [Inline HTML](#html) -+ * [Automatic Escaping for Special Characters](#autoescape) -+* [Block Elements](#block) -+ * [Paragraphs and Line Breaks](#p) -+ * [Headers](#header) -+ * [Blockquotes](#blockquote) -+ * [Lists](#list) -+ * [Code Blocks](#precode) -+ * [Horizontal Rules](#hr) -+* [Span Elements](#span) -+ * [Links](#link) -+ * [Emphasis](#em) -+ * [Code](#code) -+ * [Images](#img) -+* [Miscellaneous](#misc) -+ * [Backslash Escapes](#backslash) -+ * [Automatic Links](#autolink) -+ -+ -+**Note:** This document is itself written using Markdown; you -+can [see the source for it by adding '.text' to the URL][src]. -+ -+ [src]: /projects/markdown/syntax.text -+ -+* * * -+ -+<h2 id="overview">Overview</h2> -+ -+<h3 id="philosophy">Philosophy</h3> -+ -+Markdown is intended to be as easy-to-read and easy-to-write as is feasible. -+ -+Readability, however, is emphasized above all else. A Markdown-formatted -+document should be publishable as-is, as plain text, without looking -+like it's been marked up with tags or formatting instructions. While -+Markdown's syntax has been influenced by several existing text-to-HTML -+filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], -+[Grutatext] [5], and [EtText] [6] -- the single biggest source of -+inspiration for Markdown's syntax is the format of plain text email. -+ -+ [1]: http://docutils.sourceforge.net/mirror/setext.html -+ [2]: http://www.aaronsw.com/2002/atx/ -+ [3]: http://textism.com/tools/textile/ -+ [4]: http://docutils.sourceforge.net/rst.html -+ [5]: http://www.triptico.com/software/grutatxt.html -+ [6]: http://ettext.taint.org/doc/ -+ -+To this end, Markdown's syntax is comprised entirely of punctuation -+characters, which punctuation characters have been carefully chosen so -+as to look like what they mean. E.g., asterisks around a word actually -+look like \*emphasis\*. Markdown lists look like, well, lists. Even -+blockquotes look like quoted passages of text, assuming you've ever -+used email. -+ -+ -+ -+<h3 id="html">Inline HTML</h3> -+ -+Markdown's syntax is intended for one purpose: to be used as a -+format for *writing* for the web. -+ -+Markdown is not a replacement for HTML, or even close to it. Its -+syntax is very small, corresponding only to a very small subset of -+HTML tags. The idea is *not* to create a syntax that makes it easier -+to insert HTML tags. In my opinion, HTML tags are already easy to -+insert. The idea for Markdown is to make it easy to read, write, and -+edit prose. HTML is a *publishing* format; Markdown is a *writing* -+format. Thus, Markdown's formatting syntax only addresses issues that -+can be conveyed in plain text. -+ -+For any markup that is not covered by Markdown's syntax, you simply -+use HTML itself. There's no need to preface it or delimit it to -+indicate that you're switching from Markdown to HTML; you just use -+the tags. -+ -+The only restrictions are that block-level HTML elements -- e.g. `<div>`, -+`<table>`, `<pre>`, `<p>`, etc. -- must be separated from surrounding -+content by blank lines, and the start and end tags of the block should -+not be indented with tabs or spaces. Markdown is smart enough not -+to add extra (unwanted) `<p>` tags around HTML block-level tags. -+ -+For example, to add an HTML table to a Markdown article: -+ -+ This is a regular paragraph. -+ -+ <table> -+ <tr> -+ <td>Foo</td> -+ </tr> -+ </table> -+ -+ This is another regular paragraph. -+ -+Note that Markdown formatting syntax is not processed within block-level -+HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an -+HTML block. -+ -+Span-level HTML tags -- e.g. `<span>`, `<cite>`, or `<del>` -- can be -+used anywhere in a Markdown paragraph, list item, or header. If you -+want, you can even use HTML tags instead of Markdown formatting; e.g. if -+you'd prefer to use HTML `<a>` or `<img>` tags instead of Markdown's -+link or image syntax, go right ahead. -+ -+Unlike block-level HTML tags, Markdown syntax *is* processed within -+span-level tags. -+ -+ -+<h3 id="autoescape">Automatic Escaping for Special Characters</h3> -+ -+In HTML, there are two characters that demand special treatment: `<` -+and `&`. Left angle brackets are used to start tags; ampersands are -+used to denote HTML entities. If you want to use them as literal -+characters, you must escape them as entities, e.g. `<`, and -+`&`. -+ -+Ampersands in particular are bedeviling for web writers. If you want to -+write about 'AT&T', you need to write '`AT&T`'. You even need to -+escape ampersands within URLs. Thus, if you want to link to: -+ -+ http://images.google.com/images?num=30&q=larry+bird -+ -+you need to encode the URL as: -+ -+ http://images.google.com/images?num=30&q=larry+bird -+ -+in your anchor tag `href` attribute. Needless to say, this is easy to -+forget, and is probably the single most common source of HTML validation -+errors in otherwise well-marked-up web sites. -+ -+Markdown allows you to use these characters naturally, taking care of -+all the necessary escaping for you. If you use an ampersand as part of -+an HTML entity, it remains unchanged; otherwise it will be translated -+into `&`. -+ -+So, if you want to include a copyright symbol in your article, you can write: -+ -+ © -+ -+and Markdown will leave it alone. But if you write: -+ -+ AT&T -+ -+Markdown will translate it to: -+ -+ AT&T -+ -+Similarly, because Markdown supports [inline HTML](#html), if you use -+angle brackets as delimiters for HTML tags, Markdown will treat them as -+such. But if you write: -+ -+ 4 < 5 -+ -+Markdown will translate it to: -+ -+ 4 < 5 -+ -+However, inside Markdown code spans and blocks, angle brackets and -+ampersands are *always* encoded automatically. This makes it easy to use -+Markdown to write about HTML code. (As opposed to raw HTML, which is a -+terrible format for writing about HTML syntax, because every single `<` -+and `&` in your example code needs to be escaped.) -+ -+ -+* * * -+ -+ -+<h2 id="block">Block Elements</h2> -+ -+ -+<h3 id="p">Paragraphs and Line Breaks</h3> -+ -+A paragraph is simply one or more consecutive lines of text, separated -+by one or more blank lines. (A blank line is any line that looks like a -+blank line -- a line containing nothing but spaces or tabs is considered -+blank.) Normal paragraphs should not be intended with spaces or tabs. -+ -+The implication of the "one or more consecutive lines of text" rule is -+that Markdown supports "hard-wrapped" text paragraphs. This differs -+significantly from most other text-to-HTML formatters (including Movable -+Type's "Convert Line Breaks" option) which translate every line break -+character in a paragraph into a `<br />` tag. -+ -+When you *do* want to insert a `<br />` break tag using Markdown, you -+end a line with two or more spaces, then type return. -+ -+Yes, this takes a tad more effort to create a `<br />`, but a simplistic -+"every line break is a `<br />`" rule wouldn't work for Markdown. -+Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] -+work best -- and look better -- when you format them with hard breaks. -+ -+ [bq]: #blockquote -+ [l]: #list -+ -+ -+ -+<h3 id="header">Headers</h3> -+ -+Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. -+ -+Setext-style headers are "underlined" using equal signs (for first-level -+headers) and dashes (for second-level headers). For example: -+ -+ This is an H1 -+ ============= -+ -+ This is an H2 -+ ------------- -+ -+Any number of underlining `=`'s or `-`'s will work. -+ -+Atx-style headers use 1-6 hash characters at the start of the line, -+corresponding to header levels 1-6. For example: -+ -+ # This is an H1 -+ -+ ## This is an H2 -+ -+ ###### This is an H6 -+ -+Optionally, you may "close" atx-style headers. This is purely -+cosmetic -- you can use this if you think it looks better. The -+closing hashes don't even need to match the number of hashes -+used to open the header. (The number of opening hashes -+determines the header level.) : -+ -+ # This is an H1 # -+ -+ ## This is an H2 ## -+ -+ ### This is an H3 ###### -+ -+ -+<h3 id="blockquote">Blockquotes</h3> -+ -+Markdown uses email-style `>` characters for blockquoting. If you're -+familiar with quoting passages of text in an email message, then you -+know how to create a blockquote in Markdown. It looks best if you hard -+wrap the text and put a `>` before every line: -+ -+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, -+ > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. -+ > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. -+ > -+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse -+ > id sem consectetuer libero luctus adipiscing. -+ -+Markdown allows you to be lazy and only put the `>` before the first -+line of a hard-wrapped paragraph: -+ -+ > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, -+ consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. -+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. -+ -+ > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse -+ id sem consectetuer libero luctus adipiscing. -+ -+Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by -+adding additional levels of `>`: -+ -+ > This is the first level of quoting. -+ > -+ > > This is nested blockquote. -+ > -+ > Back to the first level. -+ -+Blockquotes can contain other Markdown elements, including headers, lists, -+and code blocks: -+ -+ > ## This is a header. -+ > -+ > 1. This is the first list item. -+ > 2. This is the second list item. -+ > -+ > Here's some example code: -+ > -+ > return shell_exec("echo $input | $markdown_script"); -+ -+Any decent text editor should make email-style quoting easy. For -+example, with BBEdit, you can make a selection and choose Increase -+Quote Level from the Text menu. -+ -+ -+<h3 id="list">Lists</h3> -+ -+Markdown supports ordered (numbered) and unordered (bulleted) lists. -+ -+Unordered lists use asterisks, pluses, and hyphens -- interchangably -+-- as list markers: -+ -+ * Red -+ * Green -+ * Blue -+ -+is equivalent to: -+ -+ + Red -+ + Green -+ + Blue -+ -+and: -+ -+ - Red -+ - Green -+ - Blue -+ -+Ordered lists use numbers followed by periods: -+ -+ 1. Bird -+ 2. McHale -+ 3. Parish -+ -+It's important to note that the actual numbers you use to mark the -+list have no effect on the HTML output Markdown produces. The HTML -+Markdown produces from the above list is: -+ -+ <ol> -+ <li>Bird</li> -+ <li>McHale</li> -+ <li>Parish</li> -+ </ol> -+ -+If you instead wrote the list in Markdown like this: -+ -+ 1. Bird -+ 1. McHale -+ 1. Parish -+ -+or even: -+ -+ 3. Bird -+ 1. McHale -+ 8. Parish -+ -+you'd get the exact same HTML output. The point is, if you want to, -+you can use ordinal numbers in your ordered Markdown lists, so that -+the numbers in your source match the numbers in your published HTML. -+But if you want to be lazy, you don't have to. -+ -+If you do use lazy list numbering, however, you should still start the -+list with the number 1. At some point in the future, Markdown may support -+starting ordered lists at an arbitrary number. -+ -+List markers typically start at the left margin, but may be indented by -+up to three spaces. List markers must be followed by one or more spaces -+or a tab. -+ -+To make lists look nice, you can wrap items with hanging indents: -+ -+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. -+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, -+ viverra nec, fringilla in, laoreet vitae, risus. -+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. -+ Suspendisse id sem consectetuer libero luctus adipiscing. -+ -+But if you want to be lazy, you don't have to: -+ -+ * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. -+ Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, -+ viverra nec, fringilla in, laoreet vitae, risus. -+ * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. -+ Suspendisse id sem consectetuer libero luctus adipiscing. -+ -+If list items are separated by blank lines, Markdown will wrap the -+items in `<p>` tags in the HTML output. For example, this input: -+ -+ * Bird -+ * Magic -+ -+will turn into: -+ -+ <ul> -+ <li>Bird</li> -+ <li>Magic</li> -+ </ul> -+ -+But this: -+ -+ * Bird -+ -+ * Magic -+ -+will turn into: -+ -+ <ul> -+ <li><p>Bird</p></li> -+ <li><p>Magic</p></li> -+ </ul> -+ -+List items may consist of multiple paragraphs. Each subsequent -+paragraph in a list item must be intended by either 4 spaces -+or one tab: -+ -+ 1. This is a list item with two paragraphs. Lorem ipsum dolor -+ sit amet, consectetuer adipiscing elit. Aliquam hendrerit -+ mi posuere lectus. -+ -+ Vestibulum enim wisi, viverra nec, fringilla in, laoreet -+ vitae, risus. Donec sit amet nisl. Aliquam semper ipsum -+ sit amet velit. -+ -+ 2. Suspendisse id sem consectetuer libero luctus adipiscing. -+ -+It looks nice if you indent every line of the subsequent -+paragraphs, but here again, Markdown will allow you to be -+lazy: -+ -+ * This is a list item with two paragraphs. -+ -+ This is the second paragraph in the list item. You're -+ only required to indent the first line. Lorem ipsum dolor -+ sit amet, consectetuer adipiscing elit. -+ -+ * Another item in the same list. -+ -+To put a blockquote within a list item, the blockquote's `>` -+delimiters need to be indented: -+ -+ * A list item with a blockquote: -+ -+ > This is a blockquote -+ > inside a list item. -+ -+To put a code block within a list item, the code block needs -+to be indented *twice* -- 8 spaces or two tabs: -+ -+ * A list item with a code block: -+ -+ <code goes here> -+ -+ -+It's worth noting that it's possible to trigger an ordered list by -+accident, by writing something like this: -+ -+ 1986. What a great season. -+ -+In other words, a *number-period-space* sequence at the beginning of a -+line. To avoid this, you can backslash-escape the period: -+ -+ 1986\. What a great season. -+ -+ -+ -+<h3 id="precode">Code Blocks</h3> -+ -+Pre-formatted code blocks are used for writing about programming or -+markup source code. Rather than forming normal paragraphs, the lines -+of a code block are interpreted literally. Markdown wraps a code block -+in both `<pre>` and `<code>` tags. -+ -+To produce a code block in Markdown, simply indent every line of the -+block by at least 4 spaces or 1 tab. For example, given this input: -+ -+ This is a normal paragraph: -+ -+ This is a code block. -+ -+Markdown will generate: -+ -+ <p>This is a normal paragraph:</p> -+ -+ <pre><code>This is a code block. -+ </code></pre> -+ -+One level of indentation -- 4 spaces or 1 tab -- is removed from each -+line of the code block. For example, this: -+ -+ Here is an example of AppleScript: -+ -+ tell application "Foo" -+ beep -+ end tell -+ -+will turn into: -+ -+ <p>Here is an example of AppleScript:</p> -+ -+ <pre><code>tell application "Foo" -+ beep -+ end tell -+ </code></pre> -+ -+A code block continues until it reaches a line that is not indented -+(or the end of the article). -+ -+Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) -+are automatically converted into HTML entities. This makes it very -+easy to include example HTML source code using Markdown -- just paste -+it and indent it, and Markdown will handle the hassle of encoding the -+ampersands and angle brackets. For example, this: -+ -+ <div class="footer"> -+ © 2004 Foo Corporation -+ </div> -+ -+will turn into: -+ -+ <pre><code><div class="footer"> -+ &copy; 2004 Foo Corporation -+ </div> -+ </code></pre> -+ -+Regular Markdown syntax is not processed within code blocks. E.g., -+asterisks are just literal asterisks within a code block. This means -+it's also easy to use Markdown to write about Markdown's own syntax. -+ -+ -+ -+<h3 id="hr">Horizontal Rules</h3> -+ -+You can produce a horizontal rule tag (`<hr />`) by placing three or -+more hyphens, asterisks, or underscores on a line by themselves. If you -+wish, you may use spaces between the hyphens or asterisks. Each of the -+following lines will produce a horizontal rule: -+ -+ * * * -+ -+ *** -+ -+ ***** -+ -+ - - - -+ -+ --------------------------------------- -+ -+ _ _ _ -+ -+ -+* * * -+ -+<h2 id="span">Span Elements</h2> -+ -+<h3 id="link">Links</h3> -+ -+Markdown supports two style of links: *inline* and *reference*. -+ -+In both styles, the link text is delimited by [square brackets]. -+ -+To create an inline link, use a set of regular parentheses immediately -+after the link text's closing square bracket. Inside the parentheses, -+put the URL where you want the link to point, along with an *optional* -+title for the link, surrounded in quotes. For example: -+ -+ This is [an example](http://example.com/ "Title") inline link. -+ -+ [This link](http://example.net/) has no title attribute. -+ -+Will produce: -+ -+ <p>This is <a href="http://example.com/" title="Title"> -+ an example</a> inline link.</p> -+ -+ <p><a href="http://example.net/">This link</a> has no -+ title attribute.</p> -+ -+If you're referring to a local resource on the same server, you can -+use relative paths: -+ -+ See my [About](/about/) page for details. -+ -+Reference-style links use a second set of square brackets, inside -+which you place a label of your choosing to identify the link: -+ -+ This is [an example][id] reference-style link. -+ -+You can optionally use a space to separate the sets of brackets: -+ -+ This is [an example] [id] reference-style link. -+ -+Then, anywhere in the document, you define your link label like this, -+on a line by itself: -+ -+ [id]: http://example.com/ "Optional Title Here" -+ -+That is: -+ -+* Square brackets containing the link identifier (optionally -+ indented from the left margin using up to three spaces); -+* followed by a colon; -+* followed by one or more spaces (or tabs); -+* followed by the URL for the link; -+* optionally followed by a title attribute for the link, enclosed -+ in double or single quotes. -+ -+The link URL may, optionally, be surrounded by angle brackets: -+ -+ [id]: <http://example.com/> "Optional Title Here" -+ -+You can put the title attribute on the next line and use extra spaces -+or tabs for padding, which tends to look better with longer URLs: -+ -+ [id]: http://example.com/longish/path/to/resource/here -+ "Optional Title Here" -+ -+Link definitions are only used for creating links during Markdown -+processing, and are stripped from your document in the HTML output. -+ -+Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links: -+ -+ [link text][a] -+ [link text][A] -+ -+are equivalent. -+ -+The *implicit link name* shortcut allows you to omit the name of the -+link, in which case the link text itself is used as the name. -+Just use an empty set of square brackets -- e.g., to link the word -+"Google" to the google.com web site, you could simply write: -+ -+ [Google][] -+ -+And then define the link: -+ -+ [Google]: http://google.com/ -+ -+Because link names may contain spaces, this shortcut even works for -+multiple words in the link text: -+ -+ Visit [Daring Fireball][] for more information. -+ -+And then define the link: -+ -+ [Daring Fireball]: http://daringfireball.net/ -+ -+Link definitions can be placed anywhere in your Markdown document. I -+tend to put them immediately after each paragraph in which they're -+used, but if you want, you can put them all at the end of your -+document, sort of like footnotes. -+ -+Here's an example of reference links in action: -+ -+ I get 10 times more traffic from [Google] [1] than from -+ [Yahoo] [2] or [MSN] [3]. -+ -+ [1]: http://google.com/ "Google" -+ [2]: http://search.yahoo.com/ "Yahoo Search" -+ [3]: http://search.msn.com/ "MSN Search" -+ -+Using the implicit link name shortcut, you could instead write: -+ -+ I get 10 times more traffic from [Google][] than from -+ [Yahoo][] or [MSN][]. -+ -+ [google]: http://google.com/ "Google" -+ [yahoo]: http://search.yahoo.com/ "Yahoo Search" -+ [msn]: http://search.msn.com/ "MSN Search" -+ -+Both of the above examples will produce the following HTML output: -+ -+ <p>I get 10 times more traffic from <a href="http://google.com/" -+ title="Google">Google</a> than from -+ <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a> -+ or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p> -+ -+For comparison, here is the same paragraph written using -+Markdown's inline link style: -+ -+ I get 10 times more traffic from [Google](http://google.com/ "Google") -+ than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or -+ [MSN](http://search.msn.com/ "MSN Search"). -+ -+The point of reference-style links is not that they're easier to -+write. The point is that with reference-style links, your document -+source is vastly more readable. Compare the above examples: using -+reference-style links, the paragraph itself is only 81 characters -+long; with inline-style links, it's 176 characters; and as raw HTML, -+it's 234 characters. In the raw HTML, there's more markup than there -+is text. -+ -+With Markdown's reference-style links, a source document much more -+closely resembles the final output, as rendered in a browser. By -+allowing you to move the markup-related metadata out of the paragraph, -+you can add links without interrupting the narrative flow of your -+prose. -+ -+ -+<h3 id="em">Emphasis</h3> -+ -+Markdown treats asterisks (`*`) and underscores (`_`) as indicators of -+emphasis. Text wrapped with one `*` or `_` will be wrapped with an -+HTML `<em>` tag; double `*`'s or `_`'s will be wrapped with an HTML -+`<strong>` tag. E.g., this input: -+ -+ *single asterisks* -+ -+ _single underscores_ -+ -+ **double asterisks** -+ -+ __double underscores__ -+ -+will produce: -+ -+ <em>single asterisks</em> -+ -+ <em>single underscores</em> -+ -+ <strong>double asterisks</strong> -+ -+ <strong>double underscores</strong> -+ -+You can use whichever style you prefer; the lone restriction is that -+the same character must be used to open and close an emphasis span. -+ -+Emphasis can be used in the middle of a word: -+ -+ un*fucking*believable -+ -+But if you surround an `*` or `_` with spaces, it'll be treated as a -+literal asterisk or underscore. -+ -+To produce a literal asterisk or underscore at a position where it -+would otherwise be used as an emphasis delimiter, you can backslash -+escape it: -+ -+ \*this text is surrounded by literal asterisks\* -+ -+ -+ -+<h3 id="code">Code</h3> -+ -+To indicate a span of code, wrap it with backtick quotes (`` ` ``). -+Unlike a pre-formatted code block, a code span indicates code within a -+normal paragraph. For example: -+ -+ Use the `printf()` function. -+ -+will produce: -+ -+ <p>Use the <code>printf()</code> function.</p> -+ -+To include a literal backtick character within a code span, you can use -+multiple backticks as the opening and closing delimiters: -+ -+ ``There is a literal backtick (`) here.`` -+ -+which will produce this: -+ -+ <p><code>There is a literal backtick (`) here.</code></p> -+ -+The backtick delimiters surrounding a code span may include spaces -- -+one after the opening, one before the closing. This allows you to place -+literal backtick characters at the beginning or end of a code span: -+ -+ A single backtick in a code span: `` ` `` -+ -+ A backtick-delimited string in a code span: `` `foo` `` -+ -+will produce: -+ -+ <p>A single backtick in a code span: <code>`</code></p> -+ -+ <p>A backtick-delimited string in a code span: <code>`foo`</code></p> -+ -+With a code span, ampersands and angle brackets are encoded as HTML -+entities automatically, which makes it easy to include example HTML -+tags. Markdown will turn this: -+ -+ Please don't use any `<blink>` tags. -+ -+into: -+ -+ <p>Please don't use any <code><blink></code> tags.</p> -+ -+You can write this: -+ -+ `—` is the decimal-encoded equivalent of `—`. -+ -+to produce: -+ -+ <p><code>&#8212;</code> is the decimal-encoded -+ equivalent of <code>&mdash;</code>.</p> -+ -+ -+ -+<h3 id="img">Images</h3> -+ -+Admittedly, it's fairly difficult to devise a "natural" syntax for -+placing images into a plain text document format. -+ -+Markdown uses an image syntax that is intended to resemble the syntax -+for links, allowing for two styles: *inline* and *reference*. -+ -+Inline image syntax looks like this: -+ -+  -+ -+  -+ -+That is: -+ -+* An exclamation mark: `!`; -+* followed by a set of square brackets, containing the `alt` -+ attribute text for the image; -+* followed by a set of parentheses, containing the URL or path to -+ the image, and an optional `title` attribute enclosed in double -+ or single quotes. -+ -+Reference-style image syntax looks like this: -+ -+ ![Alt text][id] -+ -+Where "id" is the name of a defined image reference. Image references -+are defined using syntax identical to link references: -+ -+ [id]: url/to/image "Optional title attribute" -+ -+As of this writing, Markdown has no syntax for specifying the -+dimensions of an image; if this is important to you, you can simply -+use regular HTML `<img>` tags. -+ -+ -+* * * -+ -+ -+<h2 id="misc">Miscellaneous</h2> -+ -+<h3 id="autolink">Automatic Links</h3> -+ -+Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: -+ -+ <http://example.com/> -+ -+Markdown will turn this into: -+ -+ <a href="http://example.com/">http://example.com/</a> -+ -+Automatic links for email addresses work similarly, except that -+Markdown will also perform a bit of randomized decimal and hex -+entity-encoding to help obscure your address from address-harvesting -+spambots. For example, Markdown will turn this: -+ -+ <address@example.com> -+ -+into something like this: -+ -+ <a href="mailto:addre -+ ss@example.co -+ m">address@exa -+ mple.com</a> -+ -+which will render in a browser as a clickable link to "address@example.com". -+ -+(This sort of entity-encoding trick will indeed fool many, if not -+most, address-harvesting bots, but it definitely won't fool all of -+them. It's better than nothing, but an address published in this way -+will probably eventually start receiving spam.) -+ -+ -+ -+<h3 id="backslash">Backslash Escapes</h3> -+ -+Markdown allows you to use backslash escapes to generate literal -+characters which would otherwise have special meaning in Markdown's -+formatting syntax. For example, if you wanted to surround a word with -+literal asterisks (instead of an HTML `<em>` tag), you can backslashes -+before the asterisks, like this: -+ -+ \*literal asterisks\* -+ -+Markdown provides backslash escapes for the following characters: -+ -+ \ backslash -+ ` backtick -+ * asterisk -+ _ underscore -+ {} curly braces -+ [] square brackets -+ () parentheses -+ # hash mark -+ + plus sign -+ - minus sign (hyphen) -+ . dot -+ ! exclamation mark -+ -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html -new file mode 100644 -index 0000000..538bb4f ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.html -@@ -0,0 +1,9 @@ -+<blockquote> -+<p>foo</p> -+ -+<blockquote> -+<p>bar</p> -+</blockquote> -+ -+<p>foo</p> -+</blockquote> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text -new file mode 100644 -index 0000000..ed3c624 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Nested blockquotes.text -@@ -0,0 +1,5 @@ -+> foo -+> -+> > bar -+> -+> foo -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html -new file mode 100644 -index 0000000..d6fa427 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.html -@@ -0,0 +1,166 @@ -+<h2>Unordered</h2> -+ -+<p>Asterisks tight:</p> -+ -+<ul> -+<li>asterisk 1</li> -+<li>asterisk 2</li> -+<li>asterisk 3</li> -+</ul> -+ -+<p>Asterisks loose:</p> -+ -+<ul> -+<li><p>asterisk 1</p></li> -+ -+<li><p>asterisk 2</p></li> -+ -+<li><p>asterisk 3</p></li> -+</ul> -+ -+<hr> -+ -+<p>Pluses tight:</p> -+ -+<ul> -+<li>Plus 1</li> -+<li>Plus 2</li> -+<li>Plus 3</li> -+</ul> -+ -+<p>Pluses loose:</p> -+ -+<ul> -+<li><p>Plus 1</p></li> -+ -+<li><p>Plus 2</p></li> -+ -+<li><p>Plus 3</p></li> -+</ul> -+ -+<hr> -+ -+<p>Minuses tight:</p> -+ -+<ul> -+<li>Minus 1</li> -+<li>Minus 2</li> -+<li>Minus 3</li> -+</ul> -+ -+<p>Minuses loose:</p> -+ -+<ul> -+<li><p>Minus 1</p></li> -+ -+<li><p>Minus 2</p></li> -+ -+<li><p>Minus 3</p></li> -+</ul> -+ -+<h2>Ordered</h2> -+ -+<p>Tight:</p> -+ -+<ol> -+<li>First</li> -+<li>Second</li> -+<li>Third</li> -+</ol> -+ -+<p>and:</p> -+ -+<ol> -+<li>One</li> -+<li>Two</li> -+<li>Three</li> -+</ol> -+ -+<p>Loose using tabs:</p> -+ -+<ol> -+<li><p>First</p></li> -+ -+<li><p>Second</p></li> -+ -+<li><p>Third</p></li> -+</ol> -+ -+<p>and using spaces:</p> -+ -+<ol> -+<li><p>One</p></li> -+ -+<li><p>Two</p></li> -+ -+<li><p>Three</p></li> -+</ol> -+ -+<p>Multiple paragraphs:</p> -+ -+<ol> -+<li><p>Item 1, graf one.</p> -+ -+<p>Item 2. graf two. The quick brown fox jumped over the lazy dog's -+back.</p></li> -+ -+<li><p>Item 2.</p></li> -+ -+<li><p>Item 3.</p></li> -+</ol> -+ -+<h2>Nested</h2> -+ -+<ul> -+<li>Tab -+ -+<ul> -+<li>Tab -+ -+<ul> -+<li>Tab</li> -+</ul></li> -+</ul></li> -+</ul> -+ -+<p>Here's another:</p> -+ -+<ol> -+<li>First</li> -+<li>Second: -+ -+<ul> -+<li>Fee</li> -+<li>Fie</li> -+<li>Foe</li> -+</ul></li> -+<li>Third</li> -+</ol> -+ -+<p>Same thing but with paragraphs:</p> -+ -+<ol> -+<li><p>First</p></li> -+ -+<li><p>Second:</p> -+ -+<ul> -+<li>Fee</li> -+<li>Fie</li> -+<li>Foe</li> -+</ul></li> -+ -+<li><p>Third</p></li> -+</ol> -+ -+<p>This was an error in Markdown 1.0.1:</p> -+ -+<ul> -+<li><p>this</p> -+ -+<ul> -+<li>sub</li> -+</ul> -+ -+<p>that</p></li> -+</ul> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text -new file mode 100644 -index 0000000..7f3b497 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Ordered and unordered lists.text -@@ -0,0 +1,131 @@ -+## Unordered -+ -+Asterisks tight: -+ -+* asterisk 1 -+* asterisk 2 -+* asterisk 3 -+ -+ -+Asterisks loose: -+ -+* asterisk 1 -+ -+* asterisk 2 -+ -+* asterisk 3 -+ -+* * * -+ -+Pluses tight: -+ -++ Plus 1 -++ Plus 2 -++ Plus 3 -+ -+ -+Pluses loose: -+ -++ Plus 1 -+ -++ Plus 2 -+ -++ Plus 3 -+ -+* * * -+ -+ -+Minuses tight: -+ -+- Minus 1 -+- Minus 2 -+- Minus 3 -+ -+ -+Minuses loose: -+ -+- Minus 1 -+ -+- Minus 2 -+ -+- Minus 3 -+ -+ -+## Ordered -+ -+Tight: -+ -+1. First -+2. Second -+3. Third -+ -+and: -+ -+1. One -+2. Two -+3. Three -+ -+ -+Loose using tabs: -+ -+1. First -+ -+2. Second -+ -+3. Third -+ -+and using spaces: -+ -+1. One -+ -+2. Two -+ -+3. Three -+ -+Multiple paragraphs: -+ -+1. Item 1, graf one. -+ -+ Item 2. graf two. The quick brown fox jumped over the lazy dog's -+ back. -+ -+2. Item 2. -+ -+3. Item 3. -+ -+ -+ -+## Nested -+ -+* Tab -+ * Tab -+ * Tab -+ -+Here's another: -+ -+1. First -+2. Second: -+ * Fee -+ * Fie -+ * Foe -+3. Third -+ -+Same thing but with paragraphs: -+ -+1. First -+ -+2. Second: -+ * Fee -+ * Fie -+ * Foe -+ -+3. Third -+ -+ -+This was an error in Markdown 1.0.1: -+ -+* this -+ -+ * sub -+ -+ that -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html -new file mode 100644 -index 0000000..71ec78c ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.html -@@ -0,0 +1,7 @@ -+<p><strong><em>This is strong and em.</em></strong></p> -+ -+<p>So is <strong><em>this</em></strong> word.</p> -+ -+<p><strong><em>This is strong and em.</em></strong></p> -+ -+<p>So is <strong><em>this</em></strong> word.</p> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text -new file mode 100644 -index 0000000..95ee690 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Strong and em together.text -@@ -0,0 +1,7 @@ -+***This is strong and em.*** -+ -+So is ***this*** word. -+ -+___This is strong and em.___ -+ -+So is ___this___ word. -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html -new file mode 100644 -index 0000000..64006d9 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.html -@@ -0,0 +1,26 @@ -+<ul> -+<li><p>this is a list item -+indented with tabs</p></li> -+ -+<li><p>this is a list item -+indented with spaces</p></li> -+</ul> -+ -+<p>Code:</p> -+ -+<pre><code>this code block is indented by one tab -+</code></pre> -+ -+<p>And:</p> -+ -+<pre><code> this code block is indented by two tabs -+</code></pre> -+ -+<p>And:</p> -+ -+<pre><code>+ this is an example list item -+ indented with tabs -+ -++ this is an example list item -+ indented with spaces -+</code></pre> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text -new file mode 100644 -index 0000000..589d113 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tabs.text -@@ -0,0 +1,21 @@ -++ this is a list item -+ indented with tabs -+ -++ this is a list item -+ indented with spaces -+ -+Code: -+ -+ this code block is indented by one tab -+ -+And: -+ -+ this code block is indented by two tabs -+ -+And: -+ -+ + this is an example list item -+ indented with tabs -+ -+ + this is an example list item -+ indented with spaces -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html -new file mode 100644 -index 0000000..9c45b69 ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.html -@@ -0,0 +1,9 @@ -+<blockquote> -+<p>A list within a blockquote:</p> -+ -+<ul> -+<li>asterisk 1</li> -+<li>asterisk 2</li> -+<li>asterisk 3</li> -+</ul> -+</blockquote> -diff --git a/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text -new file mode 100644 -index 0000000..5f18b8d ---- /dev/null -+++ b/vendor/src/github.com/russross/blackfriday/testdata/Tidyness.text -@@ -0,0 +1,5 @@ -+> A list within a blockquote: -+> -+> * asterisk 1 -+> * asterisk 2 -+> * asterisk 3 -diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml b/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml -new file mode 100644 -index 0000000..aaee9cf ---- /dev/null -+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/.travis.yml -@@ -0,0 +1,10 @@ -+language: go -+go: -+ - 1.4 -+install: -+ - go get golang.org/x/tools/cmd/vet -+script: -+ - go get -t -v ./... -+ - diff -u <(echo -n) <(gofmt -d ./) -+ - go tool vet ./ -+ - go test -v -race ./... -diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md b/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md -new file mode 100644 -index 0000000..089c440 ---- /dev/null -+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/README.md -@@ -0,0 +1,25 @@ -+sanitized_anchor_name [](https://travis-ci.org/shurcooL/sanitized_anchor_name) -+===================== -+ -+Package `sanitized_anchor_name` provides a func to create sanitized anchor names. -+ -+Its logic can be reused by multiple packages to create interoperable anchor names and links to those anchors. -+ -+At this time, it does not try to ensure that generated anchor names are unique, that responsibility falls on the caller. -+ -+Example -+======= -+ -+```Go -+anchorName := sanitized_anchor_name.Create("This is a header") -+ -+fmt.Println(anchorName) -+ -+// Output: -+// this-is-a-header -+``` -+ -+License -+------- -+ -+- [MIT License](http://opensource.org/licenses/mit-license.php) -diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go -new file mode 100644 -index 0000000..72a8753 ---- /dev/null -+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main.go -@@ -0,0 +1,29 @@ -+// Package sanitized_anchor_name provides a func to create sanitized anchor names. -+// -+// Its logic can be reused by multiple packages to create interoperable anchor names -+// and links to those anchors. -+// -+// At this time, it does not try to ensure that generated anchor names -+// are unique, that responsibility falls on the caller. -+package sanitized_anchor_name // import "github.com/shurcooL/sanitized_anchor_name" -+ -+import "unicode" -+ -+// Create returns a sanitized anchor name for the given text. -+func Create(text string) string { -+ var anchorName []rune -+ var futureDash = false -+ for _, r := range []rune(text) { -+ switch { -+ case unicode.IsLetter(r) || unicode.IsNumber(r): -+ if futureDash && len(anchorName) > 0 { -+ anchorName = append(anchorName, '-') -+ } -+ futureDash = false -+ anchorName = append(anchorName, unicode.ToLower(r)) -+ default: -+ futureDash = true -+ } -+ } -+ return string(anchorName) -+} -diff --git a/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go -new file mode 100644 -index 0000000..ad03201 ---- /dev/null -+++ b/vendor/src/github.com/shurcooL/sanitized_anchor_name/main_test.go -@@ -0,0 +1,35 @@ -+package sanitized_anchor_name_test -+ -+import ( -+ "fmt" -+ -+ "github.com/shurcooL/sanitized_anchor_name" -+) -+ -+func ExampleCreate() { -+ anchorName := sanitized_anchor_name.Create("This is a header") -+ -+ fmt.Println(anchorName) -+ -+ // Output: -+ // this-is-a-header -+} -+ -+func ExampleCreate2() { -+ fmt.Println(sanitized_anchor_name.Create("This is a header")) -+ fmt.Println(sanitized_anchor_name.Create("This is also a header")) -+ fmt.Println(sanitized_anchor_name.Create("main.go")) -+ fmt.Println(sanitized_anchor_name.Create("Article 123")) -+ fmt.Println(sanitized_anchor_name.Create("<- Let's try this, shall we?")) -+ fmt.Printf("%q\n", sanitized_anchor_name.Create(" ")) -+ fmt.Println(sanitized_anchor_name.Create("Hello, 世界")) -+ -+ // Output: -+ // this-is-a-header -+ // this-is-also-a-header -+ // main-go -+ // article-123 -+ // let-s-try-this-shall-we -+ // "" -+ // hello-世界 -+} --- -1.8.3.1 - diff --git a/SOURCES/libcontainer.patch b/SOURCES/libcontainer.patch new file mode 100644 index 0000000..488507e --- /dev/null +++ b/SOURCES/libcontainer.patch @@ -0,0 +1,552 @@ +From 60cabaf0b8591b8e2bf6644114d8846adaf3239b Mon Sep 17 00:00:00 2001 +From: Mrunal Patel <mrunalp@gmail.com> +Date: Fri, 9 Oct 2015 17:48:51 -0400 +Subject: [PATCH] Pick latest changes to libcontainer/user package + +Signed-off-by: Mrunal Patel <mrunalp@gmail.com> +--- + .../opencontainers/runc/libcontainer/user/user.go | 39 +- + .../runc/libcontainer/user/user_test.go | 472 +++++++++++++++++++++ + 2 files changed, 494 insertions(+), 17 deletions(-) + create mode 100644 vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go + +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go +index 964e31b..e6375ea 100644 +--- a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user.go +@@ -349,21 +349,26 @@ func GetExecUser(userSpec string, defaults *ExecUser, passwd, group io.Reader) ( + return user, nil + } + +-// GetAdditionalGroups looks up a list of groups by name or group id against +-// against the given /etc/group formatted data. If a group name cannot be found, +-// an error will be returned. If a group id cannot be found, it will be returned +-// as-is. ++// GetAdditionalGroups looks up a list of groups by name or group id ++// against the given /etc/group formatted data. If a group name cannot ++// be found, an error will be returned. If a group id cannot be found, ++// or the given group data is nil, the id will be returned as-is ++// provided it is in the legal range. + func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, error) { +- groups, err := ParseGroupFilter(group, func(g Group) bool { +- for _, ag := range additionalGroups { +- if g.Name == ag || strconv.Itoa(g.Gid) == ag { +- return true ++ var groups = []Group{} ++ if group != nil { ++ var err error ++ groups, err = ParseGroupFilter(group, func(g Group) bool { ++ for _, ag := range additionalGroups { ++ if g.Name == ag || strconv.Itoa(g.Gid) == ag { ++ return true ++ } + } ++ return false ++ }) ++ if err != nil { ++ return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) + } +- return false +- }) +- if err != nil { +- return nil, fmt.Errorf("Unable to find additional groups %v: %v", additionalGroups, err) + } + + gidMap := make(map[int]struct{}) +@@ -401,13 +406,13 @@ func GetAdditionalGroups(additionalGroups []string, group io.Reader) ([]int, err + return gids, nil + } + +-// Wrapper around GetAdditionalGroups that opens the groupPath given and gives +-// it as an argument to GetAdditionalGroups. ++// GetAdditionalGroupsPath is a wrapper around GetAdditionalGroups ++// that opens the groupPath given and gives it as an argument to ++// GetAdditionalGroups. + func GetAdditionalGroupsPath(additionalGroups []string, groupPath string) ([]int, error) { + group, err := os.Open(groupPath) +- if err != nil { +- return nil, fmt.Errorf("Failed to open group file: %v", err) ++ if err == nil { ++ defer group.Close() + } +- defer group.Close() + return GetAdditionalGroups(additionalGroups, group) + } +diff --git a/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go +new file mode 100644 +index 0000000..53b2289 +--- /dev/null ++++ b/vendor/src/github.com/opencontainers/runc/libcontainer/user/user_test.go +@@ -0,0 +1,472 @@ ++package user ++ ++import ( ++ "io" ++ "reflect" ++ "sort" ++ "strconv" ++ "strings" ++ "testing" ++) ++ ++func TestUserParseLine(t *testing.T) { ++ var ( ++ a, b string ++ c []string ++ d int ++ ) ++ ++ parseLine("", &a, &b) ++ if a != "" || b != "" { ++ t.Fatalf("a and b should be empty ('%v', '%v')", a, b) ++ } ++ ++ parseLine("a", &a, &b) ++ if a != "a" || b != "" { ++ t.Fatalf("a should be 'a' and b should be empty ('%v', '%v')", a, b) ++ } ++ ++ parseLine("bad boys:corny cows", &a, &b) ++ if a != "bad boys" || b != "corny cows" { ++ t.Fatalf("a should be 'bad boys' and b should be 'corny cows' ('%v', '%v')", a, b) ++ } ++ ++ parseLine("", &c) ++ if len(c) != 0 { ++ t.Fatalf("c should be empty (%#v)", c) ++ } ++ ++ parseLine("d,e,f:g:h:i,j,k", &c, &a, &b, &c) ++ if a != "g" || b != "h" || len(c) != 3 || c[0] != "i" || c[1] != "j" || c[2] != "k" { ++ t.Fatalf("a should be 'g', b should be 'h', and c should be ['i','j','k'] ('%v', '%v', '%#v')", a, b, c) ++ } ++ ++ parseLine("::::::::::", &a, &b, &c) ++ if a != "" || b != "" || len(c) != 0 { ++ t.Fatalf("a, b, and c should all be empty ('%v', '%v', '%#v')", a, b, c) ++ } ++ ++ parseLine("not a number", &d) ++ if d != 0 { ++ t.Fatalf("d should be 0 (%v)", d) ++ } ++ ++ parseLine("b:12:c", &a, &d, &b) ++ if a != "b" || b != "c" || d != 12 { ++ t.Fatalf("a should be 'b' and b should be 'c', and d should be 12 ('%v', '%v', %v)", a, b, d) ++ } ++} ++ ++func TestUserParsePasswd(t *testing.T) { ++ users, err := ParsePasswdFilter(strings.NewReader(` ++root:x:0:0:root:/root:/bin/bash ++adm:x:3:4:adm:/var/adm:/bin/false ++this is just some garbage data ++`), nil) ++ if err != nil { ++ t.Fatalf("Unexpected error: %v", err) ++ } ++ if len(users) != 3 { ++ t.Fatalf("Expected 3 users, got %v", len(users)) ++ } ++ if users[0].Uid != 0 || users[0].Name != "root" { ++ t.Fatalf("Expected users[0] to be 0 - root, got %v - %v", users[0].Uid, users[0].Name) ++ } ++ if users[1].Uid != 3 || users[1].Name != "adm" { ++ t.Fatalf("Expected users[1] to be 3 - adm, got %v - %v", users[1].Uid, users[1].Name) ++ } ++} ++ ++func TestUserParseGroup(t *testing.T) { ++ groups, err := ParseGroupFilter(strings.NewReader(` ++root:x:0:root ++adm:x:4:root,adm,daemon ++this is just some garbage data ++`), nil) ++ if err != nil { ++ t.Fatalf("Unexpected error: %v", err) ++ } ++ if len(groups) != 3 { ++ t.Fatalf("Expected 3 groups, got %v", len(groups)) ++ } ++ if groups[0].Gid != 0 || groups[0].Name != "root" || len(groups[0].List) != 1 { ++ t.Fatalf("Expected groups[0] to be 0 - root - 1 member, got %v - %v - %v", groups[0].Gid, groups[0].Name, len(groups[0].List)) ++ } ++ if groups[1].Gid != 4 || groups[1].Name != "adm" || len(groups[1].List) != 3 { ++ t.Fatalf("Expected groups[1] to be 4 - adm - 3 members, got %v - %v - %v", groups[1].Gid, groups[1].Name, len(groups[1].List)) ++ } ++} ++ ++func TestValidGetExecUser(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ defaultExecUser := ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ } ++ ++ tests := []struct { ++ ref string ++ expected ExecUser ++ }{ ++ { ++ ref: "root", ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{0, 1234}, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "adm", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 43, ++ Sgids: []int{1234}, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "root:adm", ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 43, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "adm:1234", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "42:1234", ++ expected: ExecUser{ ++ Uid: 42, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: "/var/adm", ++ }, ++ }, ++ { ++ ref: "1337:1234", ++ expected: ExecUser{ ++ Uid: 1337, ++ Gid: 1234, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ { ++ ref: "1337", ++ expected: ExecUser{ ++ Uid: 1337, ++ Gid: defaultExecUser.Gid, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ { ++ ref: "", ++ expected: ExecUser{ ++ Uid: defaultExecUser.Uid, ++ Gid: defaultExecUser.Gid, ++ Sgids: defaultExecUser.Sgids, ++ Home: defaultExecUser.Home, ++ }, ++ }, ++ } ++ ++ for _, test := range tests { ++ passwd := strings.NewReader(passwdContent) ++ group := strings.NewReader(groupContent) ++ ++ execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) ++ if err != nil { ++ t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) ++ t.Fail() ++ continue ++ } ++ ++ if !reflect.DeepEqual(test.expected, *execUser) { ++ t.Logf("got: %#v", execUser) ++ t.Logf("expected: %#v", test.expected) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestInvalidGetExecUser(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ ++ tests := []string{ ++ // No such user/group. ++ "notuser", ++ "notuser:notgroup", ++ "root:notgroup", ++ "notuser:adm", ++ "8888:notgroup", ++ "notuser:8888", ++ ++ // Invalid user/group values. ++ "-1:0", ++ "0:-3", ++ "-5:-2", ++ } ++ ++ for _, test := range tests { ++ passwd := strings.NewReader(passwdContent) ++ group := strings.NewReader(groupContent) ++ ++ execUser, err := GetExecUser(test, nil, passwd, group) ++ if err == nil { ++ t.Logf("got unexpected success when parsing '%s': %#v", test, execUser) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestGetExecUserNilSources(t *testing.T) { ++ const passwdContent = ` ++root:x:0:0:root user:/root:/bin/bash ++adm:x:42:43:adm:/var/adm:/bin/false ++this is just some garbage data ++` ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++this is just some garbage data ++` ++ ++ defaultExecUser := ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ } ++ ++ tests := []struct { ++ ref string ++ passwd, group bool ++ expected ExecUser ++ }{ ++ { ++ ref: "", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 8888, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ { ++ ref: "root", ++ passwd: true, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{8888}, ++ Home: "/root", ++ }, ++ }, ++ { ++ ref: "0", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 8888, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ { ++ ref: "0:0", ++ passwd: false, ++ group: false, ++ expected: ExecUser{ ++ Uid: 0, ++ Gid: 0, ++ Sgids: []int{8888}, ++ Home: "/8888", ++ }, ++ }, ++ } ++ ++ for _, test := range tests { ++ var passwd, group io.Reader ++ ++ if test.passwd { ++ passwd = strings.NewReader(passwdContent) ++ } ++ ++ if test.group { ++ group = strings.NewReader(groupContent) ++ } ++ ++ execUser, err := GetExecUser(test.ref, &defaultExecUser, passwd, group) ++ if err != nil { ++ t.Logf("got unexpected error when parsing '%s': %s", test.ref, err.Error()) ++ t.Fail() ++ continue ++ } ++ ++ if !reflect.DeepEqual(test.expected, *execUser) { ++ t.Logf("got: %#v", execUser) ++ t.Logf("expected: %#v", test.expected) ++ t.Fail() ++ continue ++ } ++ } ++} ++ ++func TestGetAdditionalGroups(t *testing.T) { ++ const groupContent = ` ++root:x:0:root ++adm:x:43: ++grp:x:1234:root,adm ++adm:x:4343:root,adm-duplicate ++this is just some garbage data ++` ++ tests := []struct { ++ groups []string ++ expected []int ++ hasError bool ++ }{ ++ { ++ // empty group ++ groups: []string{}, ++ expected: []int{}, ++ }, ++ { ++ // single group ++ groups: []string{"adm"}, ++ expected: []int{43}, ++ }, ++ { ++ // multiple groups ++ groups: []string{"adm", "grp"}, ++ expected: []int{43, 1234}, ++ }, ++ { ++ // invalid group ++ groups: []string{"adm", "grp", "not-exist"}, ++ expected: nil, ++ hasError: true, ++ }, ++ { ++ // group with numeric id ++ groups: []string{"43"}, ++ expected: []int{43}, ++ }, ++ { ++ // group with unknown numeric id ++ groups: []string{"adm", "10001"}, ++ expected: []int{43, 10001}, ++ }, ++ { ++ // groups specified twice with numeric and name ++ groups: []string{"adm", "43"}, ++ expected: []int{43}, ++ }, ++ { ++ // groups with too small id ++ groups: []string{"-1"}, ++ expected: nil, ++ hasError: true, ++ }, ++ { ++ // groups with too large id ++ groups: []string{strconv.Itoa(1 << 31)}, ++ expected: nil, ++ hasError: true, ++ }, ++ } ++ ++ for _, test := range tests { ++ group := strings.NewReader(groupContent) ++ ++ gids, err := GetAdditionalGroups(test.groups, group) ++ if test.hasError && err == nil { ++ t.Errorf("Parse(%#v) expects error but has none", test) ++ continue ++ } ++ if !test.hasError && err != nil { ++ t.Errorf("Parse(%#v) has error %v", test, err) ++ continue ++ } ++ sort.Sort(sort.IntSlice(gids)) ++ if !reflect.DeepEqual(gids, test.expected) { ++ t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) ++ } ++ } ++} ++ ++func TestGetAdditionalGroupsNumeric(t *testing.T) { ++ tests := []struct { ++ groups []string ++ expected []int ++ hasError bool ++ }{ ++ { ++ // numeric groups only ++ groups: []string{"1234", "5678"}, ++ expected: []int{1234, 5678}, ++ }, ++ { ++ // numeric and alphabetic ++ groups: []string{"1234", "fake"}, ++ expected: nil, ++ hasError: true, ++ }, ++ } ++ ++ for _, test := range tests { ++ gids, err := GetAdditionalGroups(test.groups, nil) ++ if test.hasError && err == nil { ++ t.Errorf("Parse(%#v) expects error but has none", test) ++ continue ++ } ++ if !test.hasError && err != nil { ++ t.Errorf("Parse(%#v) has error %v", test, err) ++ continue ++ } ++ sort.Sort(sort.IntSlice(gids)) ++ if !reflect.DeepEqual(gids, test.expected) { ++ t.Errorf("Gids(%v), expect %v from groups %v", gids, test.expected, test.groups) ++ } ++ } ++} diff --git a/SOURCES/unpin-python-requests-requirement.patch b/SOURCES/unpin-python-requests-requirement.patch deleted file mode 100644 index 3438d24..0000000 --- a/SOURCES/unpin-python-requests-requirement.patch +++ /dev/null @@ -1,22 +0,0 @@ -From bac73612078c5adf14baf052fbb757caf8ba674e Mon Sep 17 00:00:00 2001 -From: Lokesh Mandvekar <lsm5@fedoraproject.org> -Date: Mon, 10 Aug 2015 14:17:08 -0400 -Subject: [PATCH] set python-requests requirement to >= 2.5.3 - -Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> ---- - requirements.txt | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/requirements.txt b/requirements.txt -index b23ea48..d4c33e5 100644 ---- a/requirements.txt -+++ b/requirements.txt -@@ -1,3 +1,3 @@ --requests==2.5.3 -+requests>=2.5.3 - six>=1.3.0 - websocket-client==0.32.0 --- -1.8.3.1 - diff --git a/SOURCES/urlparse.patch b/SOURCES/urlparse.patch deleted file mode 100644 index c91503f..0000000 --- a/SOURCES/urlparse.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 33ea4eb39f2b4c12f8ec88b71f9cad968f02eeef Mon Sep 17 00:00:00 2001 -From: Lokesh Mandvekar <lsm5@fedoraproject.org> -Date: Mon, 10 Aug 2015 13:54:04 -0400 -Subject: [PATCH] import urlparse if six.moves.urllib.parse unavailable - -Signed-off-by: Lokesh Mandvekar <lsm5@fedoraproject.org> ---- - websocket/_url.py | 6 +++++- - 1 file changed, 5 insertions(+), 1 deletion(-) - -diff --git a/websocket/_url.py b/websocket/_url.py -index 703b715..8667521 100644 ---- a/websocket/_url.py -+++ b/websocket/_url.py -@@ -20,7 +20,11 @@ Copyright (C) 2010 Hiroki Ohtani(liris) - - """ - --from six.moves.urllib.parse import urlparse -+try: -+ from six.moves.urllib.parse import urlparse -+except: -+ import urlparse -+ - import os - - __all__ = ["parse_url", "get_proxy_info"] --- -1.8.3.1 - diff --git a/SPECS/docker.spec b/SPECS/docker.spec index 20017bc..cf06415 100644 --- a/SPECS/docker.spec +++ b/SPECS/docker.spec @@ -2,51 +2,34 @@ # modifying the dockerinit binary breaks the SHA1 sum check by docker %global __os_install_post %{_rpmconfigdir}/brp-compress -# no python3 subpackage for docker-py -%global with_python3 0 - -# for python-websocket-client, prefix with w_ -%global w_modname websocket -%global w_distname websocket-client -%global w_eggname websocket_client -%global w_version 0.32.0 - -# for docker-python, prefix with dp_ -%global dp_version 1.4.0 -%global dp_commit 54a154d8b251df5e4788570dac4bea3cfa70b199 -%global dp_shortcommit %(c=%{dp_commit}; echo ${c:0:7}) - #debuginfo not supported with Go %global debug_package %{nil} %global provider_tld com %global provider github %global project docker -%global repo docker +%global repo %{project} %global common_path %{provider}.%{provider_tld}/%{project} -%global d_version 1.7.1 +%global d_version 1.8.2 %global import_path %{common_path}/%{repo} %global import_path_libcontainer %{common_path}/libcontainer -%global d_commit 446ad9bd9e8ec218aff5b22529c0bdc6df69d0e2 +%global d_commit bb472f05c975b343fb13e55325a985f4ac1d0ca2 %global d_shortcommit %(c=%{d_commit}; echo ${c:0:7}) -%global atomic_commit 011a826ff8b35f1d206a3de6f37fdb0292c948c9 -%global atomic_shortcommit %(c=%{atomic_commit}; echo ${c:0:7}) - %global utils_commit dab51acd1b1a77f7cb01a1b7e2129ec85c846b71 -# docker-selinux stuff (prefix with ds_ for version/release etc.) +# %%{name}-selinux stuff (prefix with ds_ for version/release etc.) # Some bits borrowed from the openstack-selinux package -%global ds_commit 6267b8324424e5ac7eb57a91243474b32dd2d965 +%global ds_commit 44abd21628c8f4c054343f12d609d03de4644234 %global ds_shortcommit %(c=%{ds_commit}; echo ${c:0:7}) %global selinuxtype targeted %global moduletype services -%global modulenames %{repo} +%global modulenames %{name} -# docker-storage-setup stuff (prefix with dss_ for version/release etc.) -%global dss_libdir %{_prefix}/lib/docker-storage-setup -%global dss_commit d3b9ba74525192f02cefc993b77a476b879974fb +# %%{name}-storage-setup stuff (prefix with dss_ for version/release etc.) +%global dss_libdir %{_prefix}/lib/%{name}-storage-setup +%global dss_commit 6898d433f7c7666475656ab89565ec02d08c4c55 %global dss_shortcommit %(c=%{dss_commit}; echo ${c:0:7}) # Usage: _format var format @@ -55,53 +38,46 @@ %global _format() export %1=""; for x in %{modulenames}; do %1+=%2; %1+=" "; done; # Relabel files -%global relabel_files() %{_sbindir}/restorecon -R %{_bindir}/%{repo} %{_localstatedir}/run/%{repo}.sock %{_localstatedir}/run/%{repo}.pid %{_sharedstatedir}/%{repo} %{_sysconfdir}/%{repo} %{_localstatedir}/log/%{repo} %{_localstatedir}/log/lxc %{_localstatedir}/lock/lxc %{_unitdir}/%{repo}.service %{_sysconfdir}/%{repo} &> /dev/null || : +%global relabel_files() %{_sbindir}/restorecon -R %{_bindir}/%{repo} %{_localstatedir}/run/%{repo}.sock %{_localstatedir}/run/%{repo}.pid %{_sysconfdir}/%{repo} %{_localstatedir}/log/%{repo} %{_localstatedir}/log/lxc %{_localstatedir}/lock/lxc %{_unitdir}/%{repo}.service %{_sysconfdir}/%{repo} &> /dev/null || : # Version of SELinux we were using +%if 0%{?fedora} >= 22 +%global selinux_policyver 3.13.1-119 +%else %global selinux_policyver 3.13.1-23 +%endif -Name: docker +Name: %{repo} Version: %{d_version} -Release: 115%{?dist} +Release: 7%{?dist} Summary: Automates deployment of containerized applications License: ASL 2.0 -URL: http://www.docker.com -# only x86_64 for now: https://github.com/docker/docker/issues/136 +URL: https://%{import_path} +# only x86_64 for now: https://%%{provider}.%%{provider_tld}/%%{name}/%%{name}/issues/136 ExclusiveArch: x86_64 -#Source0: https://%{import_path}/archive/v%{version}.tar.gz # Branch used available at -# https://github.com/rhatdan/docker/commits/rhel7-1.7 -Source0: https://github.com/rhatdan/docker/archive/%{d_commit}.tar.gz -Source1: docker.service -Source3: docker.sysconfig -Source4: docker-storage.sysconfig -Source5: docker-logrotate.sh -Source6: README.docker-logrotate -Source7: docker-network.sysconfig -# Source8 is the source tarball for python-websocket-client -Source8: http://pypi.python.org/packages/source/w/%{w_distname}/%{w_eggname}-%{w_version}.tar.gz -# Source9 is the source tarball for docker-py -Source9: http://github.com/rhatdan/docker-py/archive/%{dp_commit}.tar.gz -# Source10 is the source tarball for atomic -Source10: https://github.com/projectatomic/atomic/archive/%{atomic_commit}.tar.gz -# Source11 is the source tarball for dockertarsum and docker-fetch -Source11: https://github.com/vbatts/docker-utils/archive/%{utils_commit}.tar.gz -# Source12 is the source tarball for docker-selinux -Source12: https://github.com/fedora-cloud/%{repo}-selinux/archive/%{ds_commit}/%{repo}-selinux-%{ds_shortcommit}.tar.gz -# Source13 is the source tarball for docker-storage-setup -Source13: https://github.com/a13m/docker-storage-setup/archive/%{dss_commit}/%{repo}-storage-setup-%{dss_shortcommit}.tar.gz -Patch1: go-md2man.patch -Patch3: codegangsta-cli.patch -Patch4: urlparse.patch -Patch5: docker-py-remove-lock.patch -Patch6: 0001-Rework-patch-for-rhbz-1194445.patch -Patch7: 0001-atomic.sysconfig-use-rhel-tools-as-the-TOOLSIMG.patch -Patch8: unpin-python-requests-requirement.patch +# https://%%{provider}.%%{provider_tld}/rhatdan/%%{name}/commits/rhel7-1.8 +Source0: https://%{provider}.%{provider_tld}/rhatdan/%{name}/archive/%{d_commit}.tar.gz +Source1: %{name}.service +Source3: %{name}.sysconfig +Source4: %{name}-storage.sysconfig +Source5: %{name}-logrotate.sh +Source6: README.%{name}-logrotate +Source7: %{name}-network.sysconfig +# Source11 is the source tarball for %%{name}tarsum and %%{name}-fetch +Source11: https://%{provider}.%{provider_tld}/vbatts/%{name}-utils/archive/%{utils_commit}.tar.gz +# Source12 is the source tarball for %%{name}-selinux +Source12: https://%{provider}.%{provider_tld}/fedora-cloud/%{name}-selinux/archive/%{ds_commit}/%{name}-selinux-%{ds_shortcommit}.tar.gz +# Source13 is the source tarball for %%{name}-storage-setup +Source13: https://%{provider}.%{provider_tld}/projectatomic/%{name}-storage-setup/archive/%{dss_commit}/%{name}-storage-setup-%{dss_shortcommit}.tar.gz +Patch0: libcontainer.patch +Patch1: dev.patch BuildRequires: glibc-static -BuildRequires: golang >= 1.4.2 +BuildRequires: golang == 1.4.2 BuildRequires: device-mapper-devel BuildRequires: btrfs-progs-devel BuildRequires: sqlite-devel +BuildRequires: go-md2man BuildRequires: pkgconfig(systemd) # appropriate systemd version as per rhbz#1171054 Requires(post): systemd @@ -110,14 +86,13 @@ Requires(postun): systemd # need xz to work with ubuntu images Requires: xz Requires: device-mapper-libs >= 7:1.02.90-1 -#Requires: subscription-manager -Provides: lxc-docker = %{d_version}-%{release} -Provides: docker = %{d_version}-%{release} -Provides: docker-io = %{d_version}-%{release} +Requires: subscription-manager +Provides: lxc-%{name} = %{d_version}-%{release} +Provides: %{name}-io = %{d_version}-%{release} # RE: rhbz#1195804 - ensure min NVR for selinux-policy Requires: selinux-policy >= 3.13.1-23 -Requires(pre): %{repo}-selinux >= %{version}-%{release} +Requires(pre): %{name}-selinux >= %{version}-%{release} # rhbz#1214070 - update deps for d-s-s Requires: lvm2 >= 2.02.112 @@ -142,74 +117,14 @@ Summary: %{summary} - for running unit tests %endif %package logrotate -Summary: cron job to run logrotate on docker containers -Requires: docker = %{d_version}-%{release} -Provides: docker-io-logrotate = %{d_version}-%{release} +Summary: cron job to run logrotate on Docker containers +Requires: %{name} = %{d_version}-%{release} +Provides: %{name}-io-logrotate = %{d_version}-%{release} %description logrotate This package installs %{summary}. logrotate is assumed to be installed on containers for this to work, failures are silently ignored. -%package -n python-%{w_distname} -Summary: WebSocket client for python -Version: %{w_version} -License: LGPLv2 -BuildArch: noarch - -%description -n python-%{w_distname} -python-websocket-client module is WebSocket client for python. This -provides the low level APIs for WebSocket. All APIs are the synchronous -functions. - -python-websocket-client supports only hybi-13. - -%package python -Version: %{dp_version} -License: ASL 2.0 -Summary: An API client for docker written in Python -BuildRequires: python2-devel -BuildRequires: python-setuptools -BuildRequires: python-tools -BuildRequires: python-requests -Requires: docker >= %{d_version}-%{release} -Requires: python-requests >= 2.5.3 -Requires: python-%{w_distname} == %{w_version} -Requires: python-six >= 1.3.0 -Requires: python-argparse -Provides: python-docker-py = %{dp_version}-%{release} -Provides: python-docker = %{dp_version}-%{release} - -%description python -%{summary} - -%package -n atomic -Version: 1.0 -Summary: Tool for managing ProjectAtomic systems and containers -License: LGPLv2+ -ExclusiveArch: x86_64 -BuildRequires: python2-devel -BuildRequires: python-setuptools -BuildRequires: python-tools -BuildRequires: python-requests -BuildRequires: python-docker-py -Requires: docker -Requires: python-requests -Requires: python-docker-py >= %{dp_version}-%{release} -Requires: python-%{w_distname} >= %{w_version}-%{release} -Requires: python-six >= 1.3.0 -Conflicts: python-docker < 1.0.0-11 - -%description -n atomic -The goal of Atomic is to provide a high level, coherent entrypoint to the -system, and fill in gaps. - -For Docker, atomic can make it easier to interact with special kinds of -containers, such as super-privileged debugging tools and the like. - -The atomic host subcommand wraps rpm-ostree, currently just providing a -friendlier name, but in the future Atomic may provide more unified -management. - %package selinux Summary: SELinux policies for Docker BuildRequires: selinux-policy @@ -219,46 +134,23 @@ Requires(post): selinux-policy-targeted >= %{selinux_policyver} Requires(post): policycoreutils Requires(post): policycoreutils-python Requires(post): libselinux-utils -Provides: %{repo}-io-selinux +Provides: %{name}-io-selinux %description selinux SELinux policy modules for use with Docker. %prep -%setup -qn docker-%{d_commit} +%setup -qn %{name}-%{d_commit} +%patch0 -p1 %patch1 -p1 -%patch3 -p1 cp %{SOURCE6} . -# unpack %{repo}-selinux +# unpack %%{name}-selinux tar zxf %{SOURCE12} -# untar docker-utils tarball +# untar %%{name}-utils tarball tar zxf %{SOURCE11} -# untar python-websocket-client tarball -tar zxf %{SOURCE8} -rm -rf %{w_distname}-%{w_version}/%{w_distname}.egg-info -pushd %{w_eggname}-%{w_version} -%patch4 -p1 -popd - -# untar docker-py tarball -tar zxf %{SOURCE9} -pushd docker-py-%{dp_commit} -%patch5 -p1 -%patch6 -p1 -%patch8 -p1 -popd - -# untar atomic -tar zxf %{SOURCE10} -pushd atomic-%{atomic_commit} -sed -i '/pylint/d' Makefile -sed -i 's/go-md2man/.\/go-md2man/' Makefile -%patch7 -p1 -popd - # untar d-s-s tar zxf %{SOURCE13} @@ -266,68 +158,47 @@ tar zxf %{SOURCE13} mkdir _build pushd _build - mkdir -p src/github.com/{docker,vbatts} - ln -s $(dirs +1 -l) src/github.com/docker/docker - ln -s $(dirs +1 -l)/docker-utils-%{utils_commit} src/github.com/vbatts/docker-utils + mkdir -p src/%{provider}.%{provider_tld}/{%{name},vbatts} + ln -s $(dirs +1 -l) src/%{import_path} + ln -s $(dirs +1 -l)/%{name}-utils-%{utils_commit} src/%{provider}.%{provider_tld}/vbatts/%{name}-utils popd export DOCKER_GITCOMMIT="%{d_shortcommit}/%{d_version}" export DOCKER_BUILDTAGS='selinux btrfs_noversion' export GOPATH=$(pwd)/_build:$(pwd)/vendor:%{gopath} -# build docker binary +# build %%{name} binary sed -i '/rm -r autogen/d' hack/make.sh DEBUG=1 hack/make.sh dynbinary cp contrib/syntax/vim/LICENSE LICENSE-vim-syntax cp contrib/syntax/vim/README.md README-vim-syntax.md -# build %{repo}-selinux -pushd %{repo}-selinux-%{ds_commit} +# build %%{name}-selinux +pushd %{name}-selinux-%{ds_commit} make SHARE="%{_datadir}" TARGETS="%{modulenames}" popd pushd $(pwd)/_build/src -# build go-md2man for building manpages -go build github.com/cpuguy83/go-md2man -# build dockertarsum and docker-fetch -go build github.com/vbatts/docker-utils/cmd/docker-fetch -go build github.com/vbatts/docker-utils/cmd/dockertarsum +# build %{name}tarsum and %{name}-fetch +go build %{provider}.%{provider_tld}/vbatts/%{name}-utils/cmd/%{name}-fetch +go build %{provider}.%{provider_tld}/vbatts/%{name}-utils/cmd/%{name}tarsum popd -cp _build/src/go-md2man man/. -cp _build/src/go-md2man atomic-%{atomic_commit}/. - -sed -i 's/go-md2man/.\/go-md2man/' man/md2man-all.sh -# build docker manpages +# build %%{name} manpages man/md2man-all.sh -# build python-websocket-client -pushd %{w_eggname}-%{w_version} -%{__python} setup.py build -popd - -# build docker-py -pushd docker-py-%{dp_commit} -%{__python} setup.py build -popd - -# build atomic -pushd atomic-%{atomic_commit} -make all -popd - %install # install binary install -d %{buildroot}%{_bindir} -install -p -m 755 bundles/%{d_version}/dynbinary/docker-%{d_version} %{buildroot}%{_bindir}/docker +install -p -m 755 bundles/%{d_version}/dynbinary/%{name}-%{d_version} %{buildroot}%{_bindir}/%{name} -# install dockertarsum and docker-fetch -install -p -m 755 _build/src/docker-fetch %{buildroot}%{_bindir} -install -p -m 755 _build/src/dockertarsum %{buildroot}%{_bindir} +# install %%{name}tarsum and %%{name}-fetch +install -p -m 755 _build/src/%{name}-fetch %{buildroot}%{_bindir} +install -p -m 755 _build/src/%{name}tarsum %{buildroot}%{_bindir} -# install dockerinit -install -d %{buildroot}%{_libexecdir}/docker -install -p -m 755 bundles/%{d_version}/dynbinary/dockerinit-%{d_version} %{buildroot}%{_libexecdir}/docker/dockerinit +# install %%{name}init +install -d %{buildroot}%{_libexecdir}/%{name} +install -p -m 755 bundles/%{d_version}/dynbinary/%{name}init-%{d_version} %{buildroot}%{_libexecdir}/%{name}/%{name}init # install manpages install -d %{buildroot}%{_mandir}/man1 @@ -337,34 +208,34 @@ install -p -m 644 man/man5/* %{buildroot}%{_mandir}/man5 # install bash completion install -d %{buildroot}%{_datadir}/bash-completion/completions/ -install -p -m 644 contrib/completion/bash/docker %{buildroot}%{_datadir}/bash-completion/completions/ +install -p -m 644 contrib/completion/bash/%{name} %{buildroot}%{_datadir}/bash-completion/completions/ # install fish completion # create, install and own /usr/share/fish/vendor_completions.d until # upstream fish provides it install -dp %{buildroot}%{_datadir}/fish/vendor_completions.d -install -p -m 644 contrib/completion/fish/docker.fish %{buildroot}%{_datadir}/fish/vendor_completions.d +install -p -m 644 contrib/completion/fish/%{name}.fish %{buildroot}%{_datadir}/fish/vendor_completions.d # install container logrotate cron script install -dp %{buildroot}%{_sysconfdir}/cron.daily/ -install -p -m 755 %{SOURCE5} %{buildroot}%{_sysconfdir}/cron.daily/docker-logrotate +install -p -m 755 %{SOURCE5} %{buildroot}%{_sysconfdir}/cron.daily/%{name}-logrotate # install vim syntax highlighting install -d %{buildroot}%{_datadir}/vim/vimfiles/{doc,ftdetect,syntax} -install -p -m 644 contrib/syntax/vim/doc/dockerfile.txt %{buildroot}%{_datadir}/vim/vimfiles/doc -install -p -m 644 contrib/syntax/vim/ftdetect/dockerfile.vim %{buildroot}%{_datadir}/vim/vimfiles/ftdetect -install -p -m 644 contrib/syntax/vim/syntax/dockerfile.vim %{buildroot}%{_datadir}/vim/vimfiles/syntax +install -p -m 644 contrib/syntax/vim/doc/%{name}file.txt %{buildroot}%{_datadir}/vim/vimfiles/doc +install -p -m 644 contrib/syntax/vim/ftdetect/%{name}file.vim %{buildroot}%{_datadir}/vim/vimfiles/ftdetect +install -p -m 644 contrib/syntax/vim/syntax/%{name}file.vim %{buildroot}%{_datadir}/vim/vimfiles/syntax # install zsh completion install -d %{buildroot}%{_datadir}/zsh/site-functions -install -p -m 644 contrib/completion/zsh/_docker %{buildroot}%{_datadir}/zsh/site-functions +install -p -m 644 contrib/completion/zsh/_%{name} %{buildroot}%{_datadir}/zsh/site-functions # install udev rules install -d %{buildroot}%{_udevrulesdir} -install -p -m 755 contrib/udev/80-docker.rules %{buildroot}%{_udevrulesdir} +install -p -m 755 contrib/udev/80-%{name}.rules %{buildroot}%{_udevrulesdir} # install storage dir -install -d -m 700 %{buildroot}%{_sharedstatedir}/docker +install -d -m 700 %{buildroot}%{_sharedstatedir}/%{name} # install systemd/init scripts install -d %{buildroot}%{_unitdir} @@ -372,126 +243,97 @@ install -p -m 644 %{SOURCE1} %{buildroot}%{_unitdir} # for additional args install -d %{buildroot}%{_sysconfdir}/sysconfig/ -install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/docker -install -p -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/sysconfig/docker-storage -install -p -m 644 %{SOURCE7} %{buildroot}%{_sysconfdir}/sysconfig/docker-network +install -p -m 644 %{SOURCE3} %{buildroot}%{_sysconfdir}/sysconfig/%{name} +install -p -m 644 %{SOURCE4} %{buildroot}%{_sysconfdir}/sysconfig/%{name}-storage +install -p -m 644 %{SOURCE7} %{buildroot}%{_sysconfdir}/sysconfig/%{name}-network # install SELinux interfaces %_format INTERFACES $x.if install -d %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype} -install -p -m 644 %{repo}-selinux-%{ds_commit}/$INTERFACES %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype} +install -p -m 644 %{name}-selinux-%{ds_commit}/$INTERFACES %{buildroot}%{_datadir}/selinux/devel/include/%{moduletype} # install policy modules %_format MODULES $x.pp.bz2 install -d %{buildroot}%{_datadir}/selinux/packages -install -m 0644 %{repo}-selinux-%{ds_commit}/$MODULES %{buildroot}%{_datadir}/selinux/packages +install -m 0644 %{name}-selinux-%{ds_commit}/$MODULES %{buildroot}%{_datadir}/selinux/packages %if 0%{?with_unit_test} -install -d -m 0755 %{buildroot}%{_sharedstatedir}/docker-unit-test/ -cp -pav VERSION Dockerfile %{buildroot}%{_sharedstatedir}/docker-unit-test/. -for d in api builder cliconfig contrib daemon graph hack image integration-cli links nat opts pkg registry runconfig trust utils vendor volume; do - cp -a $d %{buildroot}%{_sharedstatedir}/docker-unit-test/ +install -d -m 0755 %{buildroot}%{_sharedstatedir}/%{name}-unit-test/ +cp -pav VERSION Dockerfile %{buildroot}%{_sharedstatedir}/%{name}-unit-test/. +for d in */ ; do + cp -a $d %{buildroot}%{_sharedstatedir}/%{name}-unit-test/ done -# remove docker.initd as it requires /sbin/runtime no packages in Fedora -rm -rf %{buildroot}%{_sharedstatedir}/docker-unit-test/contrib/init/openrc/docker.initd +# remove %%{name}.initd as it requires /sbin/runtime no packages in Fedora +rm -rf %{buildroot}%{_sharedstatedir}/%{name}-unit-test/contrib/init/openrc/%{name}.initd %endif -# remove %{repo}-selinux rpm spec file -rm -rf %{repo}-selinux-%{ds_commit}/%{repo}-selinux.spec +# remove %%{name}-selinux rpm spec file +rm -rf %{name}-selinux-%{ds_commit}/%{name}-selinux.spec # install secrets dir -#install -d -p -m 750 %{buildroot}/%{_datadir}/rhel/secrets +install -d -p -m 750 %{buildroot}/%{_datadir}/rhel/secrets # rhbz#1110876 - update symlinks for subscription management -#ln -s %{_sysconfdir}/pki/entitlement %{buildroot}%{_datadir}/rhel/secrets/etc-pki-entitlement -#ln -s %{_sysconfdir}/rhsm %{buildroot}%{_datadir}/rhel/secrets/rhsm -#ln -s %{_sysconfdir}/yum.repos.d/redhat.repo %{buildroot}%{_datadir}/rhel/secrets/rhel7.repo - -mkdir -p %{buildroot}/etc/docker/certs.d/ -#ln -s %{_sysconfdir}/rhsm/ca/redhat-uep.pem %{buildroot}/%{_sysconfdir}/docker/certs.d/redhat.com/redhat-ca.crt -#ln -s %{_sysconfdir}/rhsm/ca/redhat-uep.pem %{buildroot}/%{_sysconfdir}/docker/certs.d/redhat.io/redhat-ca.crt - -# install docker config directory -install -dp %{buildroot}%{_sysconfdir}/docker/ - -# install python-websocket-client -pushd %{w_eggname}-%{w_version} -%{__python} setup.py install -O1 --skip-build --root=%{buildroot} -mv %{buildroot}/%{_bindir}/wsdump.py \ - %{buildroot}/%{_bindir}/wsdump - -# unbundle cacert (python-websocket-client) -rm %{buildroot}/%{python2_sitelib}/%{w_modname}/cacert.pem -# And link in the mozilla ca (python-websocket-client) -ln -s /etc/pki/tls/cert.pem \ - %{buildroot}/%{python2_sitelib}/%{w_modname}/cacert.pem - -# remove tests that got installed into the buildroot (python-websocket-client) -rm -rf %{buildroot}/%{python2_sitelib}/tests/ - -# Remove executable bit from installed files. (python-websocket-client) -find %{buildroot}/%{python2_sitelib} -type f -exec chmod -x {} \; -popd +ln -s %{_sysconfdir}/pki/entitlement %{buildroot}%{_datadir}/rhel/secrets/etc-pki-entitlement +ln -s %{_sysconfdir}/rhsm %{buildroot}%{_datadir}/rhel/secrets/rhsm +ln -s %{_sysconfdir}/yum.repos.d/redhat.repo %{buildroot}%{_datadir}/rhel/secrets/rhel7.repo -# install docker-py -pushd docker-py-%{dp_commit} -%{__python} setup.py install --root %{buildroot} -popd +mkdir -p %{buildroot}/etc/%{name}/certs.d/redhat.{com,io} +ln -s %{_sysconfdir}/rhsm/ca/redhat-uep.pem %{buildroot}/%{_sysconfdir}/%{name}/certs.d/redhat.com/redhat-ca.crt +ln -s %{_sysconfdir}/rhsm/ca/redhat-uep.pem %{buildroot}/%{_sysconfdir}/%{name}/certs.d/redhat.io/redhat-ca.crt -# install atomic -pushd atomic-%{atomic_commit} -make install DESTDIR=%{buildroot} -popd +# install %%{name} config directory +install -dp %{buildroot}%{_sysconfdir}/%{name}/ -# install docker-storage-setup -pushd %{repo}-storage-setup-%{dss_commit} +# install %%{name}-storage-setup +pushd %{name}-storage-setup-%{dss_commit} install -d %{buildroot}%{_bindir} -install -p -m 755 docker-storage-setup.sh %{buildroot}%{_bindir}/docker-storage-setup +install -p -m 755 %{name}-storage-setup.sh %{buildroot}%{_bindir}/%{name}-storage-setup install -d %{buildroot}%{_unitdir} -install -p -m 644 docker-storage-setup.service %{buildroot}%{_unitdir} +install -p -m 644 %{name}-storage-setup.service %{buildroot}%{_unitdir} install -d %{buildroot}%{dss_libdir} -install -p -m 644 docker-storage-setup.conf %{buildroot}%{dss_libdir}/docker-storage-setup +install -p -m 644 %{name}-storage-setup.conf %{buildroot}%{dss_libdir}/%{name}-storage-setup install -p -m 755 libdss.sh %{buildroot}%{dss_libdir} install -d %{buildroot}%{_sysconfdir}/sysconfig -install -p -m 644 docker-storage-setup-override.conf %{buildroot}%{_sysconfdir}/sysconfig/docker-storage-setup +install -p -m 644 %{name}-storage-setup-override.conf %{buildroot}%{_sysconfdir}/sysconfig/%{name}-storage-setup install -d %{buildroot}%{_mandir}/man1 -install -p -m 644 docker-storage-setup.1 %{buildroot}%{_mandir}/man1 +install -p -m 644 %{name}-storage-setup.1 %{buildroot}%{_mandir}/man1 popd %check -[ ! -w /run/docker.sock ] || { +[ ! -w /run/%{name}.sock ] || { mkdir test_dir pushd test_dir git clone https://%{import_path} - pushd docker + pushd %{name} make test popd popd - pushd atomic-%{atomic_commit} - make test - popd } %pre -getent passwd dockerroot > /dev/null || %{_sbindir}/useradd -r -d %{_sharedstatedir}/docker -s /sbin/nologin -c "Docker User" dockerroot +getent passwd %{name}root > /dev/null || %{_sbindir}/useradd -r -d %{_sharedstatedir}/%{name} -s /sbin/nologin -c "Docker User" %{name}root exit 0 %post -%systemd_post docker.service +%systemd_post %{name}.service %post selinux # Install all modules in a single transaction %_format MODULES %{_datadir}/selinux/packages/$x.pp.bz2 %{_sbindir}/semodule -n -s %{selinuxtype} -i $MODULES if %{_sbindir}/selinuxenabled ; then -%{_sbindir}/load_policy -%relabel_files + %{_sbindir}/load_policy + %relabel_files + if [ $1 -eq 1 ]; then + restorecon -R %{_sharedstatedir}/%{repo} + fi fi %preun -%systemd_preun docker.service +%systemd_preun %{name}.service %postun -%systemd_postun_with_restart docker.service +%systemd_postun_with_restart %{name}.service %postun selinux if [ $1 -eq 0 ]; then @@ -505,83 +347,96 @@ fi %files %doc AUTHORS CHANGELOG.md CONTRIBUTING.md MAINTAINERS NOTICE %doc LICENSE* README*.md -%{_mandir}/man1/docker* +%{_mandir}/man1/%{name}* %{_mandir}/man5/* -%{_bindir}/docker -#%dir %{_datadir}/rhel -#%dir %{_datadir}/rhel/secrets -#%{_datadir}/rhel/secrets/etc-pki-entitlement -#%{_datadir}/rhel/secrets/rhel7.repo -#%{_datadir}/rhel/secrets/rhsm -%{_libexecdir}/docker -%{_unitdir}/docker.service -%config(noreplace) %{_sysconfdir}/sysconfig/docker -%config(noreplace) %{_sysconfdir}/sysconfig/docker-storage -%config(noreplace) %{_sysconfdir}/sysconfig/docker-network -%{_datadir}/bash-completion/completions/docker -%dir %{_sharedstatedir}/docker -%{_udevrulesdir}/80-docker.rules +%{_bindir}/%{name} +%dir %{_datadir}/rhel +%dir %{_datadir}/rhel/secrets +%{_datadir}/rhel/secrets/etc-pki-entitlement +%{_datadir}/rhel/secrets/rhel7.repo +%{_datadir}/rhel/secrets/rhsm +%{_libexecdir}/%{name} +%{_unitdir}/%{name}.service +%config(noreplace) %{_sysconfdir}/sysconfig/%{name} +%config(noreplace) %{_sysconfdir}/sysconfig/%{name}-storage +%config(noreplace) %{_sysconfdir}/sysconfig/%{name}-network +%{_datadir}/bash-completion/completions/%{name} +%dir %{_sharedstatedir}/%{name} +%{_udevrulesdir}/80-%{name}.rules %dir %{_datadir}/fish/vendor_completions.d/ -%{_datadir}/fish/vendor_completions.d/docker.fish +%{_datadir}/fish/vendor_completions.d/%{name}.fish %dir %{_datadir}/vim/vimfiles/doc -%{_datadir}/vim/vimfiles/doc/dockerfile.txt +%{_datadir}/vim/vimfiles/doc/%{name}file.txt %dir %{_datadir}/vim/vimfiles/ftdetect -%{_datadir}/vim/vimfiles/ftdetect/dockerfile.vim +%{_datadir}/vim/vimfiles/ftdetect/%{name}file.vim %dir %{_datadir}/vim/vimfiles/syntax -%{_datadir}/vim/vimfiles/syntax/dockerfile.vim +%{_datadir}/vim/vimfiles/syntax/%{name}file.vim %dir %{_datadir}/zsh/site-functions -%{_datadir}/zsh/site-functions/_docker -%{_sysconfdir}/docker -%{_bindir}/docker-fetch -%{_bindir}/dockertarsum -# docker-storage-setup specific -%config(noreplace) %{_sysconfdir}/sysconfig/docker-storage-setup -%{_unitdir}/docker-storage-setup.service -%{_bindir}/docker-storage-setup -%{dss_libdir}/docker-storage-setup +%{_datadir}/zsh/site-functions/_%{name} +%{_sysconfdir}/%{name} +%{_bindir}/%{name}-fetch +%{_bindir}/%{name}tarsum +# %%{name}-storage-setup specific +%config(noreplace) %{_sysconfdir}/sysconfig/%{name}-storage-setup +%{_unitdir}/%{name}-storage-setup.service +%{_bindir}/%{name}-storage-setup +%{dss_libdir}/%{name}-storage-setup %{dss_libdir}/libdss.sh %if 0%{?with_unit_test} %files unit-test -%{_sharedstatedir}/docker-unit-test/ +%{_sharedstatedir}/%{name}-unit-test/ %endif %files logrotate -%doc README.docker-logrotate -%{_sysconfdir}/cron.daily/docker-logrotate - -%files -n python-websocket-client -%doc %{w_eggname}-%{w_version}/{README.rst,LICENSE} -%{python2_sitelib}/%{w_modname}/ -%{python2_sitelib}/%{w_eggname}*%{w_version}* -%{_bindir}/wsdump - -%files python -%doc docker-py-%{dp_commit}/{LICENSE,README.md} -%{python_sitelib}/docker -%{python_sitelib}/docker_py-%{dp_version}* - -%files -n atomic -%doc atomic-%{atomic_commit}/COPYING atomic-%{atomic_commit}/README.md -%config(noreplace) %{_sysconfdir}/sysconfig/atomic -%{_sysconfdir}/profile.d/atomic.sh -%{_sysconfdir}/dbus-1/system.d/org.atomic.conf -%{_bindir}/atomic -%{_mandir}/man1/atomic* -%{_datadir}/bash-completion/completions/atomic -%{_datadir}/atomic -%{_datadir}/dbus-1/system-services/org.atomic.service -%{_datadir}/polkit-1/actions/org.atomic.policy -%{python_sitelib}/atomic*.egg-info -%{python_sitelib}/Atomic +%doc README.%{name}-logrotate +%{_sysconfdir}/cron.daily/%{name}-logrotate %files selinux -%doc %{repo}-selinux-%{ds_commit}/README.md +%doc %{name}-selinux-%{ds_commit}/README.md %{_datadir}/selinux/* %changelog -* Tue Sep 15 2015 CentOS Sources <bugs@centos.org> - 1.7.1-115.el7.centos -- comment out rh registry in docker.sysconfig +* Fri Oct 09 2015 Lokesh Mandvekar <lsm5@fedoraproject.org> - 1.8.2-7 +- https://github.com/rhatdan/docker/pull/127 (changes for libcontainer/user) +- https://github.com/rhatdan/docker/pull/128 (/dev mount from host) + +* Wed Oct 07 2015 Lokesh Mandvekar <lsm5@fedoraproject.org> - 1.8.2-6 +- built docker @rhatdan/rhel7-1.8 commit#bb472f0 +- built docker-selinux master commit#44abd21 +- built d-s-s master commit#6898d43 +- built docker-utils master commit#dab51ac + +* Wed Sep 30 2015 Lokesh Mandvekar <lsm5@fedoraproject.org> - 1.8.2-5 +- Resolves: rhbz#1267743 +- https://github.com/docker/docker/pull/16639 +- https://github.com/opencontainers/runc/commit/c9d58506297ed6c86c9d8a91d861e4de3772e699 + +* Wed Sep 30 2015 Lokesh Mandvekar <lsm5@fedoraproject.org> - 1.8.2-4 +- built docker @rhatdan/rhel7-1.8 commit#23f26d9 +- built docker-selinux master commit#2ed73eb +- built d-s-s master commit#6898d43 +- built docker-utils master commit#dab51ac + +* Wed Sep 30 2015 Lokesh Mandvekar <lsm5@fedoraproject.org> - 1.8.2-3 +- Resolves: rhbz#1264557 (extras-rhel-7.1.6) - rebase to 1.8.2 +- Resolves: rhbz#1265810 (extras-rhel-7.2) - rebase to 1.8.2 +- built docker @rhatdan/rhel7-1.8 commit#23f26d9 +- built docker-selinux master commit#d6560f8 +- built d-s-s master commit#6898d43 +- built docker-utils master commit#dab51ac +- use golang == 1.4.2 + +* Mon Sep 21 2015 Lokesh Mandvekar <lsm5@redhat.com> - 1.8.2-2 +- built docker-selinux master commit#d6560f8 + +* Fri Sep 18 2015 Lokesh Mandvekar <lsm5@redhat.com> - 1.8.2-1 +- package only provides docker, docker-selinux and docker-logrotate +- Resolves: rhbz#1261329, rhbz#1263394, rhbz#1264090 +- built docker @rhatdan/rhel7-1.8 commit#23f26d9 +- built d-s-s master commit#6898d43 +- built docker-selinux master commit#b5281b7 +- built docker-utils master commit#dab51ac * Thu Aug 27 2015 Lokesh Mandvekar <lsm5@redhat.com> - 1.7.1-115 - Resolves: rhbz#1252421