Browse Source

initial commit

Jon Lundy 2 years ago
commit
9eca3811ae
100 changed files with 17541 additions and 0 deletions
  1. 2 0
      .gitignore
  2. 4 0
      .gitmodules
  3. 149 0
      Gopkg.lock
  4. 38 0
      Gopkg.toml
  5. 24 0
      Makefile
  6. 1 0
      VERSION
  7. 152 0
      cmd/skillet/config.go
  8. 151 0
      cmd/skillet/skillet.go
  9. 1 0
      shell
  10. 25 0
      vendor/github.com/docopt/docopt-go/.gitignore
  11. 32 0
      vendor/github.com/docopt/docopt-go/.travis.yml
  12. 21 0
      vendor/github.com/docopt/docopt-go/LICENSE
  13. 116 0
      vendor/github.com/docopt/docopt-go/README.md
  14. 49 0
      vendor/github.com/docopt/docopt-go/doc.go
  15. 575 0
      vendor/github.com/docopt/docopt-go/docopt.go
  16. 49 0
      vendor/github.com/docopt/docopt-go/error.go
  17. 264 0
      vendor/github.com/docopt/docopt-go/opts.go
  18. 550 0
      vendor/github.com/docopt/docopt-go/pattern.go
  19. 9 0
      vendor/github.com/docopt/docopt-go/test_golang.docopt
  20. 957 0
      vendor/github.com/docopt/docopt-go/testcases.docopt
  21. 126 0
      vendor/github.com/docopt/docopt-go/token.go
  22. 27 0
      vendor/github.com/fluffle/goirc/LICENSE
  23. 304 0
      vendor/github.com/fluffle/goirc/client/commands.go
  24. 587 0
      vendor/github.com/fluffle/goirc/client/connection.go
  25. 202 0
      vendor/github.com/fluffle/goirc/client/dispatch.go
  26. 34 0
      vendor/github.com/fluffle/goirc/client/doc.go
  27. 105 0
      vendor/github.com/fluffle/goirc/client/handlers.go
  28. 216 0
      vendor/github.com/fluffle/goirc/client/line.go
  29. 262 0
      vendor/github.com/fluffle/goirc/client/state_handlers.go
  30. 43 0
      vendor/github.com/fluffle/goirc/logging/logging.go
  31. 350 0
      vendor/github.com/fluffle/goirc/state/channel.go
  32. 201 0
      vendor/github.com/fluffle/goirc/state/mock_tracker.go
  33. 200 0
      vendor/github.com/fluffle/goirc/state/nick.go
  34. 369 0
      vendor/github.com/fluffle/goirc/state/tracker.go
  35. 5 0
      vendor/github.com/fsnotify/fsnotify/.editorconfig
  36. 6 0
      vendor/github.com/fsnotify/fsnotify/.gitignore
  37. 30 0
      vendor/github.com/fsnotify/fsnotify/.travis.yml
  38. 52 0
      vendor/github.com/fsnotify/fsnotify/AUTHORS
  39. 317 0
      vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
  40. 77 0
      vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
  41. 28 0
      vendor/github.com/fsnotify/fsnotify/LICENSE
  42. 79 0
      vendor/github.com/fsnotify/fsnotify/README.md
  43. 37 0
      vendor/github.com/fsnotify/fsnotify/fen.go
  44. 66 0
      vendor/github.com/fsnotify/fsnotify/fsnotify.go
  45. 337 0
      vendor/github.com/fsnotify/fsnotify/inotify.go
  46. 187 0
      vendor/github.com/fsnotify/fsnotify/inotify_poller.go
  47. 521 0
      vendor/github.com/fsnotify/fsnotify/kqueue.go
  48. 11 0
      vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
  49. 12 0
      vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
  50. 561 0
      vendor/github.com/fsnotify/fsnotify/windows.go
  51. 12 0
      vendor/github.com/golang/mock/AUTHORS
  52. 37 0
      vendor/github.com/golang/mock/CONTRIBUTORS
  53. 202 0
      vendor/github.com/golang/mock/LICENSE
  54. 428 0
      vendor/github.com/golang/mock/gomock/call.go
  55. 108 0
      vendor/github.com/golang/mock/gomock/callset.go
  56. 217 0
      vendor/github.com/golang/mock/gomock/controller.go
  57. 99 0
      vendor/github.com/golang/mock/gomock/matchers.go
  58. 9 0
      vendor/github.com/hashicorp/hcl/.gitignore
  59. 13 0
      vendor/github.com/hashicorp/hcl/.travis.yml
  60. 354 0
      vendor/github.com/hashicorp/hcl/LICENSE
  61. 18 0
      vendor/github.com/hashicorp/hcl/Makefile
  62. 125 0
      vendor/github.com/hashicorp/hcl/README.md
  63. 19 0
      vendor/github.com/hashicorp/hcl/appveyor.yml
  64. 729 0
      vendor/github.com/hashicorp/hcl/decoder.go
  65. 11 0
      vendor/github.com/hashicorp/hcl/hcl.go
  66. 219 0
      vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
  67. 52 0
      vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
  68. 17 0
      vendor/github.com/hashicorp/hcl/hcl/parser/error.go
  69. 532 0
      vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
  70. 789 0
      vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go
  71. 66 0
      vendor/github.com/hashicorp/hcl/hcl/printer/printer.go
  72. 652 0
      vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
  73. 241 0
      vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
  74. 46 0
      vendor/github.com/hashicorp/hcl/hcl/token/position.go
  75. 219 0
      vendor/github.com/hashicorp/hcl/hcl/token/token.go
  76. 117 0
      vendor/github.com/hashicorp/hcl/json/parser/flatten.go
  77. 313 0
      vendor/github.com/hashicorp/hcl/json/parser/parser.go
  78. 451 0
      vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
  79. 46 0
      vendor/github.com/hashicorp/hcl/json/token/position.go
  80. 118 0
      vendor/github.com/hashicorp/hcl/json/token/token.go
  81. 38 0
      vendor/github.com/hashicorp/hcl/lex.go
  82. 39 0
      vendor/github.com/hashicorp/hcl/parse.go
  83. 6 0
      vendor/github.com/magiconair/properties/.gitignore
  84. 10 0
      vendor/github.com/magiconair/properties/.travis.yml
  85. 131 0
      vendor/github.com/magiconair/properties/CHANGELOG.md
  86. 25 0
      vendor/github.com/magiconair/properties/LICENSE
  87. 129 0
      vendor/github.com/magiconair/properties/README.md
  88. 289 0
      vendor/github.com/magiconair/properties/decode.go
  89. 156 0
      vendor/github.com/magiconair/properties/doc.go
  90. 34 0
      vendor/github.com/magiconair/properties/integrate.go
  91. 407 0
      vendor/github.com/magiconair/properties/lex.go
  92. 292 0
      vendor/github.com/magiconair/properties/load.go
  93. 95 0
      vendor/github.com/magiconair/properties/parser.go
  94. 833 0
      vendor/github.com/magiconair/properties/properties.go
  95. 31 0
      vendor/github.com/magiconair/properties/rangecheck.go
  96. 8 0
      vendor/github.com/mitchellh/mapstructure/.travis.yml
  97. 21 0
      vendor/github.com/mitchellh/mapstructure/LICENSE
  98. 46 0
      vendor/github.com/mitchellh/mapstructure/README.md
  99. 171 0
      vendor/github.com/mitchellh/mapstructure/decode_hooks.go
  100. 0 0
      vendor/github.com/mitchellh/mapstructure/error.go

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+config.inc
+bin/*

+ 4 - 0
.gitmodules

@@ -0,0 +1,4 @@
+[submodule "shell"]
+	path = shell
+	url = git@git.dn42:xuu/skillet.git
+	branch = master

+ 149 - 0
Gopkg.lock

@@ -0,0 +1,149 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  branch = "master"
+  name = "github.com/docopt/docopt-go"
+  packages = ["."]
+  revision = "ee0de3bc6815ee19d4a46c7eb90f829db0e014b1"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/fluffle/goirc"
+  packages = [
+    "client",
+    "logging",
+    "state"
+  ]
+  revision = "fc1dfa1ceb8897bcaa5231b560b9319591d4ab0a"
+
+[[projects]]
+  name = "github.com/fsnotify/fsnotify"
+  packages = ["."]
+  revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
+  version = "v1.4.7"
+
+[[projects]]
+  name = "github.com/golang/mock"
+  packages = ["gomock"]
+  revision = "c34cdb4725f4c3844d095133c6e40e448b86589b"
+  version = "v1.1.1"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/hashicorp/hcl"
+  packages = [
+    ".",
+    "hcl/ast",
+    "hcl/parser",
+    "hcl/printer",
+    "hcl/scanner",
+    "hcl/strconv",
+    "hcl/token",
+    "json/parser",
+    "json/scanner",
+    "json/token"
+  ]
+  revision = "ef8a98b0bbce4a65b5aa4c368430a80ddc533168"
+
+[[projects]]
+  name = "github.com/magiconair/properties"
+  packages = ["."]
+  revision = "c2353362d570a7bfa228149c62842019201cfb71"
+  version = "v1.8.0"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/mitchellh/mapstructure"
+  packages = ["."]
+  revision = "bb74f1db0675b241733089d5a1faa5dd8b0ef57b"
+
+[[projects]]
+  name = "github.com/pelletier/go-toml"
+  packages = ["."]
+  revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194"
+  version = "v1.2.0"
+
+[[projects]]
+  name = "github.com/spf13/afero"
+  packages = [
+    ".",
+    "mem"
+  ]
+  revision = "787d034dfe70e44075ccc060d346146ef53270ad"
+  version = "v1.1.1"
+
+[[projects]]
+  name = "github.com/spf13/cast"
+  packages = ["."]
+  revision = "8965335b8c7107321228e3e3702cab9832751bac"
+  version = "v1.2.0"
+
+[[projects]]
+  branch = "master"
+  name = "github.com/spf13/jwalterweatherman"
+  packages = ["."]
+  revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
+
+[[projects]]
+  name = "github.com/spf13/pflag"
+  packages = ["."]
+  revision = "583c0c0531f06d5278b7d917446061adc344b5cd"
+  version = "v1.0.1"
+
+[[projects]]
+  name = "github.com/spf13/viper"
+  packages = ["."]
+  revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
+  version = "v1.0.2"
+
+[[projects]]
+  branch = "master"
+  name = "golang.org/x/net"
+  packages = [
+    "context",
+    "internal/socks",
+    "proxy"
+  ]
+  revision = "d1d521f6884855bc0e59c3d011574bd0678f18bc"
+
+[[projects]]
+  branch = "master"
+  name = "golang.org/x/sys"
+  packages = ["unix"]
+  revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56"
+
+[[projects]]
+  name = "golang.org/x/text"
+  packages = [
+    "internal/gen",
+    "internal/triegen",
+    "internal/ucd",
+    "transform",
+    "unicode/cldr",
+    "unicode/norm"
+  ]
+  revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
+  version = "v0.3.0"
+
+[[projects]]
+  name = "gopkg.in/yaml.v2"
+  packages = ["."]
+  revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
+  version = "v2.2.1"
+
+[[projects]]
+  branch = "master"
+  name = "sour.is/x/toolbox"
+  packages = [
+    "log",
+    "vault"
+  ]
+  revision = "8f5007638717d8ebc706733ff8b86951274afa2b"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  inputs-digest = "1aaae05f114728afc3159eae70c682c44f7e0971f9c7b8e6a06ad619637414d7"
+  solver-name = "gps-cdcl"
+  solver-version = 1

+ 38 - 0
Gopkg.toml

@@ -0,0 +1,38 @@
+# Gopkg.toml example
+#
+# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[prune]
+  go-tests = true
+  unused-packages = true
+
+[[constraint]]
+  name = "github.com/spf13/viper"
+  version = "1.0.2"
+
+[[constraint]]
+  name = "github.com/docopt/docopt-go"
+  branch = "master"

+ 24 - 0
Makefile

@@ -0,0 +1,24 @@
+include config.inc
+
+export VERSION := $(shell cat VERSION)
+export DATE := $(shell date -u +%FT%TZ)
+
+clean:
+	rm bin/skillet
+
+bin/skillet:
+	mkdir -p bin
+	go build -v -o bin/skillet \
+    		 -ldflags "-X main.AppVersion=$${VERSION} -X main.AppBuild=$${DATE}"\
+    		 sour.is/x/skillet/cmd/skillet;
+
+bin/skillet-lnx64:
+	mkdir -p bin
+	export GOOS=linux GOARCH=amd64; \
+	go build -v -o bin/skillet-lnx64 \
+    		 -ldflags "-X main.AppVersion=$${VERSION} -X main.AppBuild=$${DATE}"\
+    		 sour.is/x/skillet/cmd/skillet
+
+run: bin/skillet
+	export
+	cd shell && ../bin/skillet -vv connect

+ 1 - 0
VERSION

@@ -0,0 +1 @@
+1.0.0

+ 152 - 0
cmd/skillet/config.go

@@ -0,0 +1,152 @@
+package main
+
+import (
+	"sour.is/x/toolbox/log"
+	"bytes"
+	"strings"
+	"os"
+	"github.com/spf13/viper"
+	"github.com/docopt/docopt-go"
+)
+
+var (
+	// AppVersion Application Version Number
+	AppVersion string
+
+	// AppBuild Application Build Number
+	AppBuild string
+)
+
+// AppName name of the application
+var AppName = "Skillet"
+
+// AppUsage displays runtime options
+var AppUsage = `Skillet
+
+Usage:
+  skillet version
+  skillet [ -v | -vv ] connect
+
+Options:
+  -v                                             Log info to console.
+  -vv                                            Log debug to console.
+  -c <ConfigDir>, --config=<ConfigDir>           Set Config Directory.
+
+Config:
+  The config file is read from the following locations:
+    - <ConfigDir>
+    - /etc/opt/sour.is/skillet/
+    - Working Directory
+`
+var defaultConfig = `
+[irc]
+`
+
+var automaticEnv = []string{
+	"irc.ssl",
+	"irc.host",
+	"irc.nick",
+	"irc.chan",
+	"irc.pass",
+	"irc.oper",
+}
+
+var args map[string]interface{}
+
+func init() {
+	initAppInfo()
+	log.Printf("%s (%s %s)\n",
+		viper.GetString("app.name"),
+		viper.GetString("app.version"),
+		viper.GetString("app.build"))
+
+	initArgs()
+	if args["connect"] == true {
+		initConfig()
+		log.StartupBanner()
+
+		//if err := vault.LoadVault(); err != nil {
+		//	log.Fatal(err)
+		//}
+
+		for k, v := range viper.AllSettings() {
+			log.Debug(k, ": ", v)
+		}
+	}
+}
+func initArgs() {
+	var err error
+
+	// Handle Command Arguments
+	if args, err = docopt.ParseDoc(AppUsage); err != nil {
+		log.Fatal(err)
+	}
+
+	if args["-v"].(int) == 1 {
+		log.SetVerbose(log.Vinfo)
+		log.Info("Verbose Logging.")
+	}
+	if args["-v"].(int) == 2 {
+		log.SetVerbose(log.Vdebug)
+		log.SetFlags(log.Lshortfile | log.LstdFlags)
+		log.Debug("Very Verbose Logging.")
+	}
+
+}
+func initConfig() {
+	var err error
+
+	viper.SetConfigType("toml")
+	err = viper.ReadConfig(bytes.NewBuffer([]byte(defaultConfig)))
+	if err != nil { // Handle errors reading the config file
+		log.Fatalf("Builtin config invalid: %s \n", err)
+	}
+
+	// Handle config files
+	viper.SetConfigName("config")
+
+	if args["--config"] != nil {
+		viper.AddConfigPath(args["--config"].(string))
+	}
+
+	// Read in config from file.
+	viper.AddConfigPath("/etc/opt/sour.is/skillet/")
+	viper.AddConfigPath(".")
+
+	err = viper.MergeInConfig()
+	if err != nil { // Handle errors reading the config file
+		log.Warningf("No config file found: %s \n", err)
+	} else {
+		log.Notice("Read config from: ", viper.ConfigFileUsed())
+	}
+
+	// Setup config from environment.
+	viper.SetEnvPrefix("skillet")
+	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
+	viper.AutomaticEnv()
+
+	for _, key := range automaticEnv {
+		if viper.GetString(key) != "" {
+			viper.Set(key, viper.Get(key))
+		}
+	}
+}
+func initAppInfo() {
+	// Setup app info
+	viper.Set("app.name", AppName)
+
+	viper.SetDefault("app.version", "VERSION")
+	if AppVersion != "" {
+		viper.Set("app.version", AppVersion)
+	}
+
+	viper.SetDefault("app.build", "SNAPSHOT")
+	if AppBuild != "" {
+		viper.Set("app.build", AppBuild)
+	}
+
+	mode := os.Getenv("MODE")
+	if mode != "" {
+		viper.Set("app.name", AppName+" "+mode)
+	}
+}

+ 151 - 0
cmd/skillet/skillet.go

@@ -0,0 +1,151 @@
+package main
+
+import (
+	"fmt"
+
+	irc "github.com/fluffle/goirc/client"
+	"crypto/tls"
+	"os"
+	"os/signal"
+	"syscall"
+	"strings"
+	"os/exec"
+	"bytes"
+	"github.com/spf13/viper"
+	"sour.is/x/toolbox/log"
+)
+
+func main () {
+	NODE, err := os.Hostname()
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	HOST := viper.GetString("irc.host")
+	NICK := viper.GetString("irc.nick")
+	CHAN := viper.GetString("irc.chan")
+	PASS := viper.GetString("irc.pass")
+	// OPER := viper.GetString("irc.oper")
+	SSL := viper.GetBool("irc.ssl")
+
+	cfg := irc.NewConfig(NICK)
+	cfg.SSL = SSL
+	cfg.SSLConfig = &tls.Config{ServerName: HOST, InsecureSkipVerify: true}
+    cfg.Server = HOST
+	cfg.NewNick = func(n string) string { return n + "^" }
+
+	c := irc.Client(cfg)
+
+	c.HandleFunc(
+		irc.REGISTER,
+		func(conn *irc.Conn, line *irc.Line) {
+			log.Println("CONNECTED ")
+			conn.Raw(fmt.Sprintf("PASS %s", PASS))
+		})
+
+	c.HandleFunc(
+		irc.CONNECTED,
+		func(conn *irc.Conn, line *irc.Line) {
+			log.Println("HOME ", CHAN)
+			conn.Join(CHAN)
+		})
+
+	c.HandleFunc(
+		irc.JOIN,
+		func(conn *irc.Conn, line *irc.Line) {
+			log.Printf("JOIN %v", line.Target())
+			if line.Target() == CHAN {
+				conn.Notice(line.Target(), fmt.Sprintf("%v@%v reporting for duty!", line.Nick, NODE))
+			}
+		})
+
+	c.HandleFunc(
+		irc.INVITE,
+		func(conn *irc.Conn, line *irc.Line) {
+			log.Printf("INVITE %v", line.Args)
+			conn.Join(line.Args[1])
+		})
+
+	c.HandleFunc(
+		irc.PRIVMSG,
+		func(conn *irc.Conn, line *irc.Line) {
+
+			tgt := strings.SplitN(line.Src, "!", 2)
+			args := []string{tgt[0], tgt[1], line.Target(), "", line.Text()}
+
+			var stdout bytes.Buffer
+			var stderr bytes.Buffer
+
+			cmd := exec.Command("hooks-enabled/pubmsg", args...)
+			cmd.Stdout = &stdout
+			cmd.Stderr = &stderr
+
+			err := cmd.Run()
+			if err != nil {
+				//if err.Error() == "exit status 2" {
+				//	return
+				//}
+
+				log.Debug("~> ", err)
+			}
+
+			for _, line := range strings.Split(stderr.String(), "\n") {
+				if line == "" { continue }
+				log.Debug("~> ", line)
+			}
+			if err != nil {
+				return
+			}
+
+			ch := line.Target()
+			mode := "NOTICE"
+			for i, line := range strings.Split(stdout.String(), "\n") {
+				if i == 0 && strings.HasPrefix(line, "+") {
+					tgt = strings.Fields(line[1:])
+					mode, ch = tgt[0], tgt[1]
+					continue
+				}
+				if line == "" { continue }
+
+				switch mode {
+				case irc.NOTICE:
+					log.Debug("N> ", line)
+					conn.Notice(ch, line)
+
+				case irc.PRIVMSG:
+					log.Debug("P> ", line)
+					conn.Privmsg(ch, line)
+				}
+			}
+
+		})
+
+	quit := make(chan bool)
+	c.HandleFunc(
+		irc.DISCONNECTED,
+		func(conn *irc.Conn, line *irc.Line) {
+			close(quit)
+		})
+
+	if err := c.Connect(); err != nil {
+		log.Errorf("Connection error: %s", err.Error())
+		close(quit)
+	}
+
+	trap := make(chan os.Signal, 1)
+	signal.Notify(trap, syscall.SIGINT, syscall.SIGTERM)
+
+	// Wait for disconnect
+QUIT:
+	for {
+		select {
+		case <-quit:
+			break QUIT
+		case <-trap:
+			log.Notice("Shutting Down")
+			c.Notice(CHAN, fmt.Sprintf("So long and thanks for all the fish! - Douglas Adams - %v@%v", NICK, NODE))
+			c.Quit("So long and thanks for all the fish!")
+		}
+	}
+}

+ 1 - 0
shell

@@ -0,0 +1 @@
+Subproject commit 7604b2191deb17d7fd850970229202c3342dec78

+ 25 - 0
vendor/github.com/docopt/docopt-go/.gitignore

@@ -0,0 +1,25 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+
+# coverage droppings
+profile.cov

+ 32 - 0
vendor/github.com/docopt/docopt-go/.travis.yml

@@ -0,0 +1,32 @@
+# Travis CI (http://travis-ci.org/) is a continuous integration
+# service for open source projects. This file configures it
+# to run unit tests for docopt-go.
+
+language: go
+
+go:
+    - 1.4
+    - 1.5
+    - 1.6
+    - 1.7
+    - 1.8
+    - 1.9
+    - tip
+
+matrix:
+    fast_finish: true
+
+before_install:
+    - go get golang.org/x/tools/cmd/cover
+    - go get github.com/mattn/goveralls
+
+install:
+    - go get -d -v ./... && go build -v ./...
+
+script:
+    - go vet -x ./...
+    - go test -v ./...
+    - go test -covermode=count -coverprofile=profile.cov .
+
+after_script:
+    - $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci

+ 21 - 0
vendor/github.com/docopt/docopt-go/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2013 Keith Batten
+Copyright (c) 2016 David Irvine
+
+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.

+ 116 - 0
vendor/github.com/docopt/docopt-go/README.md

@@ -0,0 +1,116 @@
+docopt-go
+=========
+
+[![Build Status](https://travis-ci.org/docopt/docopt.go.svg?branch=master)](https://travis-ci.org/docopt/docopt.go)
+[![Coverage Status](https://coveralls.io/repos/github/docopt/docopt.go/badge.svg)](https://coveralls.io/github/docopt/docopt.go)
+[![GoDoc](https://godoc.org/github.com/docopt/docopt.go?status.svg)](https://godoc.org/github.com/docopt/docopt.go)
+
+An implementation of [docopt](http://docopt.org/) in the [Go](http://golang.org/) programming language.
+
+**docopt** helps you create *beautiful* command-line interfaces easily:
+
+```go
+package main
+
+import (
+	"fmt"
+	"github.com/docopt/docopt-go"
+)
+
+func main() {
+	  usage := `Naval Fate.
+
+Usage:
+  naval_fate ship new <name>...
+  naval_fate ship <name> move <x> <y> [--speed=<kn>]
+  naval_fate ship shoot <x> <y>
+  naval_fate mine (set|remove) <x> <y> [--moored|--drifting]
+  naval_fate -h | --help
+  naval_fate --version
+
+Options:
+  -h --help     Show this screen.
+  --version     Show version.
+  --speed=<kn>  Speed in knots [default: 10].
+  --moored      Moored (anchored) mine.
+  --drifting    Drifting mine.`
+
+	  arguments, _ := docopt.ParseDoc(usage)
+	  fmt.Println(arguments)
+}
+```
+
+**docopt** parses command-line arguments based on a help message. Don't write parser code: a good help message already has all the necessary information in it.
+
+## Installation
+
+⚠ Use the alias "docopt-go". To use docopt in your Go code:
+
+```go
+import "github.com/docopt/docopt-go"
+```
+
+To install docopt in your `$GOPATH`:
+
+```console
+$ go get github.com/docopt/docopt-go
+```
+
+## API
+
+Given a conventional command-line help message, docopt processes the arguments. See https://github.com/docopt/docopt#help-message-format for a description of the help message format.
+
+This package exposes three different APIs, depending on the level of control required. The first, simplest way to parse your docopt usage is to just call:
+
+```go
+docopt.ParseDoc(usage)
+```
+
+This will use `os.Args[1:]` as the argv slice, and use the default parser options. If you want to provide your own version string and args, then use:
+
+```go
+docopt.ParseArgs(usage, argv, "1.2.3")
+```
+
+If the last parameter (version) is a non-empty string, it will be printed when `--version` is given in the argv slice. Finally, we can instantiate our own `docopt.Parser` which gives us control over how things like help messages are printed and whether to exit after displaying usage messages, etc.
+
+```go
+parser := &docopt.Parser{
+  HelpHandler: docopt.PrintHelpOnly,
+  OptionsFirst: true,
+}
+opts, err := parser.ParseArgs(usage, argv, "")
+```
+
+In particular, setting your own custom `HelpHandler` function makes unit testing your own docs with example command line invocations much more enjoyable.
+
+All three of these return a map of option names to the values parsed from argv, and an error or nil. You can get the values using the helpers, or just treat it as a regular map:
+
+```go
+flag, _ := opts.Bool("--flag")
+secs, _ := opts.Int("<seconds>")
+```
+
+Additionally, you can `Bind` these to a struct, assigning option values to the
+exported fields of that struct, all at once.
+
+```go
+var config struct {
+  Command string `docopt:"<cmd>"`
+  Tries   int    `docopt:"-n"`
+  Force   bool   // Gets the value of --force
+}
+opts.Bind(&config)
+```
+
+More documentation is available at [godoc.org](https://godoc.org/github.com/docopt/docopt-go).
+
+## Unit Testing
+
+Unit testing your own usage docs is recommended, so you can be sure that for a given command line invocation, the expected options are set. An example of how to do this is [in the examples folder](examples/unit_test/unit_test.go).
+
+## Tests
+
+All tests from the Python version are implemented and passing at [Travis CI](https://travis-ci.org/docopt/docopt-go). New language-agnostic tests have been added to [test_golang.docopt](test_golang.docopt).
+
+To run tests for docopt-go, use `go test`.

+ 49 - 0
vendor/github.com/docopt/docopt-go/doc.go

@@ -0,0 +1,49 @@
+/*
+Package docopt parses command-line arguments based on a help message.
+
+Given a conventional command-line help message, docopt processes the arguments.
+See https://github.com/docopt/docopt#help-message-format for a description of
+the help message format.
+
+This package exposes three different APIs, depending on the level of control
+required. The first, simplest way to parse your docopt usage is to just call:
+
+	docopt.ParseDoc(usage)
+
+This will use os.Args[1:] as the argv slice, and use the default parser
+options. If you want to provide your own version string and args, then use:
+
+	docopt.ParseArgs(usage, argv, "1.2.3")
+
+If the last parameter (version) is a non-empty string, it will be printed when
+--version is given in the argv slice. Finally, we can instantiate our own
+docopt.Parser which gives us control over how things like help messages are
+printed and whether to exit after displaying usage messages, etc.
+
+	parser := &docopt.Parser{
+		HelpHandler: docopt.PrintHelpOnly,
+		OptionsFirst: true,
+	}
+	opts, err := parser.ParseArgs(usage, argv, "")
+
+In particular, setting your own custom HelpHandler function makes unit testing
+your own docs with example command line invocations much more enjoyable.
+
+All three of these return a map of option names to the values parsed from argv,
+and an error or nil. You can get the values using the helpers, or just treat it
+as a regular map:
+
+	flag, _ := opts.Bool("--flag")
+	secs, _ := opts.Int("<seconds>")
+
+Additionally, you can `Bind` these to a struct, assigning option values to the
+exported fields of that struct, all at once.
+
+	var config struct {
+		Command string `docopt:"<cmd>"`
+		Tries   int    `docopt:"-n"`
+		Force   bool   // Gets the value of --force
+	}
+	opts.Bind(&config)
+*/
+package docopt

+ 575 - 0
vendor/github.com/docopt/docopt-go/docopt.go

@@ -0,0 +1,575 @@
+// Licensed under terms of MIT license (see LICENSE-MIT)
+// Copyright (c) 2013 Keith Batten, kbatten@gmail.com
+// Copyright (c) 2016 David Irvine
+
+package docopt
+
+import (
+	"fmt"
+	"os"
+	"regexp"
+	"strings"
+)
+
+type Parser struct {
+	// HelpHandler is called when we encounter bad user input, or when the user
+	// asks for help.
+	// By default, this calls os.Exit(0) if it handled a built-in option such
+	// as -h, --help or --version. If the user errored with a wrong command or
+	// options, we exit with a return code of 1.
+	HelpHandler func(err error, usage string)
+	// OptionsFirst requires that option flags always come before positional
+	// arguments; otherwise they can overlap.
+	OptionsFirst bool
+	// SkipHelpFlags tells the parser not to look for -h and --help flags and
+	// call the HelpHandler.
+	SkipHelpFlags bool
+}
+
+var PrintHelpAndExit = func(err error, usage string) {
+	if err != nil {
+		fmt.Fprintln(os.Stderr, usage)
+		os.Exit(1)
+	} else {
+		fmt.Println(usage)
+		os.Exit(0)
+	}
+}
+
+var PrintHelpOnly = func(err error, usage string) {
+	if err != nil {
+		fmt.Fprintln(os.Stderr, usage)
+	} else {
+		fmt.Println(usage)
+	}
+}
+
+var NoHelpHandler = func(err error, usage string) {}
+
+var DefaultParser = &Parser{
+	HelpHandler:   PrintHelpAndExit,
+	OptionsFirst:  false,
+	SkipHelpFlags: false,
+}
+
+// ParseDoc parses os.Args[1:] based on the interface described in doc, using the default parser options.
+func ParseDoc(doc string) (Opts, error) {
+	return ParseArgs(doc, nil, "")
+}
+
+// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
+// string, then this will be displayed when the --version flag is found. This method uses the default parser options.
+func ParseArgs(doc string, argv []string, version string) (Opts, error) {
+	return DefaultParser.ParseArgs(doc, argv, version)
+}
+
+// ParseArgs parses custom arguments based on the interface described in doc. If you provide a non-empty version
+// string, then this will be displayed when the --version flag is found.
+func (p *Parser) ParseArgs(doc string, argv []string, version string) (Opts, error) {
+	return p.parse(doc, argv, version)
+}
+
+// Deprecated: Parse is provided for backward compatibility with the original docopt.go package.
+// Please rather make use of ParseDoc, ParseArgs, or use your own custom Parser.
+func Parse(doc string, argv []string, help bool, version string, optionsFirst bool, exit ...bool) (map[string]interface{}, error) {
+	exitOk := true
+	if len(exit) > 0 {
+		exitOk = exit[0]
+	}
+	p := &Parser{
+		OptionsFirst:  optionsFirst,
+		SkipHelpFlags: !help,
+	}
+	if exitOk {
+		p.HelpHandler = PrintHelpAndExit
+	} else {
+		p.HelpHandler = PrintHelpOnly
+	}
+	return p.parse(doc, argv, version)
+}
+
+func (p *Parser) parse(doc string, argv []string, version string) (map[string]interface{}, error) {
+	if argv == nil {
+		argv = os.Args[1:]
+	}
+	if p.HelpHandler == nil {
+		p.HelpHandler = DefaultParser.HelpHandler
+	}
+	args, output, err := parse(doc, argv, !p.SkipHelpFlags, version, p.OptionsFirst)
+	if _, ok := err.(*UserError); ok {
+		// the user gave us bad input
+		p.HelpHandler(err, output)
+	} else if len(output) > 0 && err == nil {
+		// the user asked for help or --version
+		p.HelpHandler(err, output)
+	}
+	return args, err
+}
+
+// -----------------------------------------------------------------------------
+
+// parse and return a map of args, output and all errors
+func parse(doc string, argv []string, help bool, version string, optionsFirst bool) (args map[string]interface{}, output string, err error) {
+	if argv == nil && len(os.Args) > 1 {
+		argv = os.Args[1:]
+	}
+
+	usageSections := parseSection("usage:", doc)
+
+	if len(usageSections) == 0 {
+		err = newLanguageError("\"usage:\" (case-insensitive) not found.")
+		return
+	}
+	if len(usageSections) > 1 {
+		err = newLanguageError("More than one \"usage:\" (case-insensitive).")
+		return
+	}
+	usage := usageSections[0]
+
+	options := parseDefaults(doc)
+	formal, err := formalUsage(usage)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+
+	pat, err := parsePattern(formal, &options)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+
+	patternArgv, err := parseArgv(newTokenList(argv, errorUser), &options, optionsFirst)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	patFlat, err := pat.flat(patternOption)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	patternOptions := patFlat.unique()
+
+	patFlat, err = pat.flat(patternOptionSSHORTCUT)
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	for _, optionsShortcut := range patFlat {
+		docOptions := parseDefaults(doc)
+		optionsShortcut.children = docOptions.unique().diff(patternOptions)
+	}
+
+	if output = extras(help, version, patternArgv, doc); len(output) > 0 {
+		return
+	}
+
+	err = pat.fix()
+	if err != nil {
+		output = handleError(err, usage)
+		return
+	}
+	matched, left, collected := pat.match(&patternArgv, nil)
+	if matched && len(*left) == 0 {
+		patFlat, err = pat.flat(patternDefault)
+		if err != nil {
+			output = handleError(err, usage)
+			return
+		}
+		args = append(patFlat, *collected...).dictionary()
+		return
+	}
+
+	err = newUserError("")
+	output = handleError(err, usage)
+	return
+}
+
+func handleError(err error, usage string) string {
+	if _, ok := err.(*UserError); ok {
+		return strings.TrimSpace(fmt.Sprintf("%s\n%s", err, usage))
+	}
+	return ""
+}
+
+func parseSection(name, source string) []string {
+	p := regexp.MustCompile(`(?im)^([^\n]*` + name + `[^\n]*\n?(?:[ \t].*?(?:\n|$))*)`)
+	s := p.FindAllString(source, -1)
+	if s == nil {
+		s = []string{}
+	}
+	for i, v := range s {
+		s[i] = strings.TrimSpace(v)
+	}
+	return s
+}
+
+func parseDefaults(doc string) patternList {
+	defaults := patternList{}
+	p := regexp.MustCompile(`\n[ \t]*(-\S+?)`)
+	for _, s := range parseSection("options:", doc) {
+		// FIXME corner case "bla: options: --foo"
+		_, _, s = stringPartition(s, ":") // get rid of "options:"
+		split := p.Split("\n"+s, -1)[1:]
+		match := p.FindAllStringSubmatch("\n"+s, -1)
+		for i := range split {
+			optionDescription := match[i][1] + split[i]
+			if strings.HasPrefix(optionDescription, "-") {
+				defaults = append(defaults, parseOption(optionDescription))
+			}
+		}
+	}
+	return defaults
+}
+
+func parsePattern(source string, options *patternList) (*pattern, error) {
+	tokens := tokenListFromPattern(source)
+	result, err := parseExpr(tokens, options)
+	if err != nil {
+		return nil, err
+	}
+	if tokens.current() != nil {
+		return nil, tokens.errorFunc("unexpected ending: %s" + strings.Join(tokens.tokens, " "))
+	}
+	return newRequired(result...), nil
+}
+
+func parseArgv(tokens *tokenList, options *patternList, optionsFirst bool) (patternList, error) {
+	/*
+		Parse command-line argument vector.
+
+		If options_first:
+			argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
+		else:
+			argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
+	*/
+	parsed := patternList{}
+	for tokens.current() != nil {
+		if tokens.current().eq("--") {
+			for _, v := range tokens.tokens {
+				parsed = append(parsed, newArgument("", v))
+			}
+			return parsed, nil
+		} else if tokens.current().hasPrefix("--") {
+			pl, err := parseLong(tokens, options)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, pl...)
+		} else if tokens.current().hasPrefix("-") && !tokens.current().eq("-") {
+			ps, err := parseShorts(tokens, options)
+			if err != nil {
+				return nil, err
+			}
+			parsed = append(parsed, ps...)
+		} else if optionsFirst {
+			for _, v := range tokens.tokens {
+				parsed = append(parsed, newArgument("", v))
+			}
+			return parsed, nil
+		} else {
+			parsed = append(parsed, newArgument("", tokens.move().String()))
+		}
+	}
+	return parsed, nil
+}
+
+func parseOption(optionDescription string) *pattern {
+	optionDescription = strings.TrimSpace(optionDescription)
+	options, _, description := stringPartition(optionDescription, "  ")
+	options = strings.Replace(options, ",", " ", -1)
+	options = strings.Replace(options, "=", " ", -1)
+
+	short := ""
+	long := ""
+	argcount := 0
+	var value interface{}
+	value = false
+
+	reDefault := regexp.MustCompile(`(?i)\[default: (.*)\]`)
+	for _, s := range strings.Fields(options) {
+		if strings.HasPrefix(s, "--") {
+			long = s
+		} else if strings.HasPrefix(s, "-") {
+			short = s
+		} else {
+			argcount = 1
+		}
+		if argcount > 0 {
+			matched := reDefault.FindAllStringSubmatch(description, -1)
+			if len(matched) > 0 {
+				value = matched[0][1]
+			} else {
+				value = nil
+			}
+		}
+	}
+	return newOption(short, long, argcount, value)
+}
+
+func parseExpr(tokens *tokenList, options *patternList) (patternList, error) {
+	// expr ::= seq ( '|' seq )* ;
+	seq, err := parseSeq(tokens, options)
+	if err != nil {
+		return nil, err
+	}
+	if !tokens.current().eq("|") {
+		return seq, nil
+	}
+	var result patternList
+	if len(seq) > 1 {
+		result = patternList{newRequired(seq...)}
+	} else {
+		result = seq
+	}
+	for tokens.current().eq("|") {
+		tokens.move()
+		seq, err = parseSeq(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if len(seq) > 1 {
+			result = append(result, newRequired(seq...))
+		} else {
+			result = append(result, seq...)
+		}
+	}
+	if len(result) > 1 {
+		return patternList{newEither(result...)}, nil
+	}
+	return result, nil
+}
+
+func parseSeq(tokens *tokenList, options *patternList) (patternList, error) {
+	// seq ::= ( atom [ '...' ] )* ;
+	result := patternList{}
+	for !tokens.current().match(true, "]", ")", "|") {
+		atom, err := parseAtom(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if tokens.current().eq("...") {
+			atom = patternList{newOneOrMore(atom...)}
+			tokens.move()
+		}
+		result = append(result, atom...)
+	}
+	return result, nil
+}
+
+func parseAtom(tokens *tokenList, options *patternList) (patternList, error) {
+	// atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ;
+	tok := tokens.current()
+	result := patternList{}
+	if tokens.current().match(false, "(", "[") {
+		tokens.move()
+		var matching string
+		pl, err := parseExpr(tokens, options)
+		if err != nil {
+			return nil, err
+		}
+		if tok.eq("(") {
+			matching = ")"
+			result = patternList{newRequired(pl...)}
+		} else if tok.eq("[") {
+			matching = "]"
+			result = patternList{newOptional(pl...)}
+		}
+		moved := tokens.move()
+		if !moved.eq(matching) {
+			return nil, tokens.errorFunc("unmatched '%s', expected: '%s' got: '%s'", tok, matching, moved)
+		}
+		return result, nil
+	} else if tok.eq("options") {
+		tokens.move()
+		return patternList{newOptionsShortcut()}, nil
+	} else if tok.hasPrefix("--") && !tok.eq("--") {
+		return parseLong(tokens, options)
+	} else if tok.hasPrefix("-") && !tok.eq("-") && !tok.eq("--") {
+		return parseShorts(tokens, options)
+	} else if tok.hasPrefix("<") && tok.hasSuffix(">") || tok.isUpper() {
+		return patternList{newArgument(tokens.move().String(), nil)}, nil
+	}
+	return patternList{newCommand(tokens.move().String(), false)}, nil
+}
+
+func parseLong(tokens *tokenList, options *patternList) (patternList, error) {
+	// long ::= '--' chars [ ( ' ' | '=' ) chars ] ;
+	long, eq, v := stringPartition(tokens.move().String(), "=")
+	var value interface{}
+	var opt *pattern
+	if eq == "" && v == "" {
+		value = nil
+	} else {
+		value = v
+	}
+
+	if !strings.HasPrefix(long, "--") {
+		return nil, newError("long option '%s' doesn't start with --", long)
+	}
+	similar := patternList{}
+	for _, o := range *options {
+		if o.long == long {
+			similar = append(similar, o)
+		}
+	}
+	if tokens.err == errorUser && len(similar) == 0 { // if no exact match
+		similar = patternList{}
+		for _, o := range *options {
+			if strings.HasPrefix(o.long, long) {
+				similar = append(similar, o)
+			}
+		}
+	}
+	if len(similar) > 1 { // might be simply specified ambiguously 2+ times?
+		similarLong := make([]string, len(similar))
+		for i, s := range similar {
+			similarLong[i] = s.long
+		}
+		return nil, tokens.errorFunc("%s is not a unique prefix: %s?", long, strings.Join(similarLong, ", "))
+	} else if len(similar) < 1 {
+		argcount := 0
+		if eq == "=" {
+			argcount = 1
+		}
+		opt = newOption("", long, argcount, false)
+		*options = append(*options, opt)
+		if tokens.err == errorUser {
+			var val interface{}
+			if argcount > 0 {
+				val = value
+			} else {
+				val = true
+			}
+			opt = newOption("", long, argcount, val)
+		}
+	} else {
+		opt = newOption(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value)
+		if opt.argcount == 0 {
+			if value != nil {
+				return nil, tokens.errorFunc("%s must not have an argument", opt.long)
+			}
+		} else {
+			if value == nil {
+				if tokens.current().match(true, "--") {
+					return nil, tokens.errorFunc("%s requires argument", opt.long)
+				}
+				moved := tokens.move()
+				if moved != nil {
+					value = moved.String() // only set as string if not nil
+				}
+			}
+		}
+		if tokens.err == errorUser {
+			if value != nil {
+				opt.value = value
+			} else {
+				opt.value = true
+			}
+		}
+	}
+
+	return patternList{opt}, nil
+}
+
+func parseShorts(tokens *tokenList, options *patternList) (patternList, error) {
+	// shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;
+	tok := tokens.move()
+	if !tok.hasPrefix("-") || tok.hasPrefix("--") {
+		return nil, newError("short option '%s' doesn't start with -", tok)
+	}
+	left := strings.TrimLeft(tok.String(), "-")
+	parsed := patternList{}
+	for left != "" {
+		var opt *pattern
+		short := "-" + left[0:1]
+		left = left[1:]
+		similar := patternList{}
+		for _, o := range *options {
+			if o.short == short {
+				similar = append(similar, o)
+			}
+		}
+		if len(similar) > 1 {
+			return nil, tokens.errorFunc("%s is specified ambiguously %d times", short, len(similar))
+		} else if len(similar) < 1 {
+			opt = newOption(short, "", 0, false)
+			*options = append(*options, opt)
+			if tokens.err == errorUser {
+				opt = newOption(short, "", 0, true)
+			}
+		} else { // why copying is necessary here?
+			opt = newOption(short, similar[0].long, similar[0].argcount, similar[0].value)
+			var value interface{}
+			if opt.argcount > 0 {
+				if left == "" {
+					if tokens.current().match(true, "--") {
+						return nil, tokens.errorFunc("%s requires argument", short)
+					}
+					value = tokens.move().String()
+				} else {
+					value = left
+					left = ""
+				}
+			}
+			if tokens.err == errorUser {
+				if value != nil {
+					opt.value = value
+				} else {
+					opt.value = true
+				}
+			}
+		}
+		parsed = append(parsed, opt)
+	}
+	return parsed, nil
+}
+
+func formalUsage(section string) (string, error) {
+	_, _, section = stringPartition(section, ":") // drop "usage:"
+	pu := strings.Fields(section)
+
+	if len(pu) == 0 {
+		return "", newLanguageError("no fields found in usage (perhaps a spacing error).")
+	}
+
+	result := "( "
+	for _, s := range pu[1:] {
+		if s == pu[0] {
+			result += ") | ( "
+		} else {
+			result += s + " "
+		}
+	}
+	result += ")"
+
+	return result, nil
+}
+
+func extras(help bool, version string, options patternList, doc string) string {
+	if help {
+		for _, o := range options {
+			if (o.name == "-h" || o.name == "--help") && o.value == true {
+				return strings.Trim(doc, "\n")
+			}
+		}
+	}
+	if version != "" {
+		for _, o := range options {
+			if (o.name == "--version") && o.value == true {
+				return version
+			}
+		}
+	}
+	return ""
+}
+
+func stringPartition(s, sep string) (string, string, string) {
+	sepPos := strings.Index(s, sep)
+	if sepPos == -1 { // no seperator found
+		return s, "", ""
+	}
+	split := strings.SplitN(s, sep, 2)
+	return split[0], sep, split[1]
+}

+ 49 - 0
vendor/github.com/docopt/docopt-go/error.go

@@ -0,0 +1,49 @@
+package docopt
+
+import (
+	"fmt"
+)
+
+type errorType int
+
+const (
+	errorUser errorType = iota
+	errorLanguage
+)
+
+func (e errorType) String() string {
+	switch e {
+	case errorUser:
+		return "errorUser"
+	case errorLanguage:
+		return "errorLanguage"
+	}
+	return ""
+}
+
+// UserError records an error with program arguments.
+type UserError struct {
+	msg   string
+	Usage string
+}
+
+func (e UserError) Error() string {
+	return e.msg
+}
+func newUserError(msg string, f ...interface{}) error {
+	return &UserError{fmt.Sprintf(msg, f...), ""}
+}
+
+// LanguageError records an error with the doc string.
+type LanguageError struct {
+	msg string
+}
+
+func (e LanguageError) Error() string {
+	return e.msg
+}
+func newLanguageError(msg string, f ...interface{}) error {
+	return &LanguageError{fmt.Sprintf(msg, f...)}
+}
+
+var newError = fmt.Errorf

+ 264 - 0
vendor/github.com/docopt/docopt-go/opts.go

@@ -0,0 +1,264 @@
+package docopt
+
+import (
+	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"unicode"
+)
+
+func errKey(key string) error {
+	return fmt.Errorf("no such key: %q", key)
+}
+func errType(key string) error {
+	return fmt.Errorf("key: %q failed type conversion", key)
+}
+func errStrconv(key string, convErr error) error {
+	return fmt.Errorf("key: %q failed type conversion: %s", key, convErr)
+}
+
+// Opts is a map of command line options to their values, with some convenience
+// methods for value type conversion (bool, float64, int, string). For example,
+// to get an option value as an int:
+//
+//   opts, _ := docopt.ParseDoc("Usage: sleep <seconds>")
+//   secs, _ := opts.Int("<seconds>")
+//
+// Additionally, Opts.Bind allows you easily populate a struct's fields with the
+// values of each option value. See below for examples.
+//
+// Lastly, you can still treat Opts as a regular map, and do any type checking
+// and conversion that you want to yourself. For example:
+//
+//   if s, ok := opts["<binary>"].(string); ok {
+//     if val, err := strconv.ParseUint(s, 2, 64); err != nil { ... }
+//   }
+//
+// Note that any non-boolean option / flag will have a string value in the
+// underlying map.
+type Opts map[string]interface{}
+
+func (o Opts) String(key string) (s string, err error) {
+	v, ok := o[key]
+	if !ok {
+		err = errKey(key)
+		return
+	}
+	s, ok = v.(string)
+	if !ok {
+		err = errType(key)
+	}
+	return
+}
+
+func (o Opts) Bool(key string) (b bool, err error) {
+	v, ok := o[key]
+	if !ok {
+		err = errKey(key)
+		return
+	}
+	b, ok = v.(bool)
+	if !ok {
+		err = errType(key)
+	}
+	return
+}
+
+func (o Opts) Int(key string) (i int, err error) {
+	s, err := o.String(key)
+	if err != nil {
+		return
+	}
+	i, err = strconv.Atoi(s)
+	if err != nil {
+		err = errStrconv(key, err)
+	}
+	return
+}
+
+func (o Opts) Float64(key string) (f float64, err error) {
+	s, err := o.String(key)
+	if err != nil {
+		return
+	}
+	f, err = strconv.ParseFloat(s, 64)
+	if err != nil {
+		err = errStrconv(key, err)
+	}
+	return
+}
+
+// Bind populates the fields of a given struct with matching option values.
+// Each key in Opts will be mapped to an exported field of the struct pointed
+// to by `v`, as follows:
+//
+//   abc int                        // Unexported field, ignored
+//   Abc string                     // Mapped from `--abc`, `<abc>`, or `abc`
+//                                  // (case insensitive)
+//   A string                       // Mapped from `-a`, `<a>` or `a`
+//                                  // (case insensitive)
+//   Abc int  `docopt:"XYZ"`        // Mapped from `XYZ`
+//   Abc bool `docopt:"-"`          // Mapped from `-`
+//   Abc bool `docopt:"-x,--xyz"`   // Mapped from `-x` or `--xyz`
+//                                  // (first non-zero value found)
+//
+// Tagged (annotated) fields will always be mapped first. If no field is tagged
+// with an option's key, Bind will try to map the option to an appropriately
+// named field (as above).
+//
+// Bind also handles conversion to bool, float, int or string types.
+func (o Opts) Bind(v interface{}) error {
+	structVal := reflect.ValueOf(v)
+	if structVal.Kind() != reflect.Ptr {
+		return newError("'v' argument is not pointer to struct type")
+	}
+	for structVal.Kind() == reflect.Ptr {
+		structVal = structVal.Elem()
+	}
+	if structVal.Kind() != reflect.Struct {
+		return newError("'v' argument is not pointer to struct type")
+	}
+	structType := structVal.Type()
+
+	tagged := make(map[string]int)   // Tagged field tags
+	untagged := make(map[string]int) // Untagged field names
+
+	for i := 0; i < structType.NumField(); i++ {
+		field := structType.Field(i)
+		if isUnexportedField(field) || field.Anonymous {
+			continue
+		}
+		tag := field.Tag.Get("docopt")
+		if tag == "" {
+			untagged[field.Name] = i
+			continue
+		}
+		for _, t := range strings.Split(tag, ",") {
+			tagged[t] = i
+		}
+	}
+
+	// Get the index of the struct field to use, based on the option key.
+	// Second argument is true/false on whether something was matched.
+	getFieldIndex := func(key string) (int, bool) {
+		if i, ok := tagged[key]; ok {
+			return i, true
+		}
+		if i, ok := untagged[guessUntaggedField(key)]; ok {
+			return i, true
+		}
+		return -1, false
+	}
+
+	indexMap := make(map[string]int) // Option keys to field index
+
+	// Pre-check that option keys are mapped to fields and fields are zero valued, before populating them.
+	for k := range o {
+		i, ok := getFieldIndex(k)
+		if !ok {
+			if k == "--help" || k == "--version" { // Don't require these to be mapped.
+				continue
+			}
+			return newError("mapping of %q is not found in given struct, or is an unexported field", k)
+		}
+		fieldVal := structVal.Field(i)
+		zeroVal := reflect.Zero(fieldVal.Type())
+		if !reflect.DeepEqual(fieldVal.Interface(), zeroVal.Interface()) {
+			return newError("%q field is non-zero, will be overwritten by value of %q", structType.Field(i).Name, k)
+		}
+		indexMap[k] = i
+	}
+
+	// Populate fields with option values.
+	for k, v := range o {
+		i, ok := indexMap[k]
+		if !ok {
+			continue // Not mapped.
+		}
+		field := structVal.Field(i)
+		if !reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()) {
+			// The struct's field is already non-zero (by our doing), so don't change it.
+			// This happens with comma separated tags, e.g. `docopt:"-h,--help"` which is a
+			// convenient way of checking if one of multiple boolean flags are set.
+			continue
+		}
+		optVal := reflect.ValueOf(v)
+		// Option value is the zero Value, so we can't get its .Type(). No need to assign anyway, so move along.
+		if !optVal.IsValid() {
+			continue
+		}
+		if !field.CanSet() {
+			return newError("%q field cannot be set", structType.Field(i).Name)
+		}
+		// Try to assign now if able. bool and string values should be assignable already.
+		if optVal.Type().AssignableTo(field.Type()) {
+			field.Set(optVal)
+			continue
+		}
+		// Try to convert the value and assign if able.
+		switch field.Kind() {
+		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+			if x, err := o.Int(k); err == nil {
+				field.SetInt(int64(x))
+				continue
+			}
+		case reflect.Float32, reflect.Float64:
+			if x, err := o.Float64(k); err == nil {
+				field.SetFloat(x)
+				continue
+			}
+		}
+		// TODO: Something clever (recursive?) with non-string slices.
+		// case reflect.Slice:
+		// 	if optVal.Kind() == reflect.Slice {
+		// 		for i := 0; i < optVal.Len(); i++ {
+		// 			sliceVal := optVal.Index(i)
+		// 			fmt.Printf("%v", sliceVal)
+		// 		}
+		// 		fmt.Printf("\n")
+		// 	}
+		return newError("value of %q is not assignable to %q field", k, structType.Field(i).Name)
+	}
+
+	return nil
+}
+
+// isUnexportedField returns whether the field is unexported.
+// isUnexportedField is to avoid the bug in versions older than Go1.3.
+// See following links:
+//   https://code.google.com/p/go/issues/detail?id=7247
+//   http://golang.org/ref/spec#Exported_identifiers
+func isUnexportedField(field reflect.StructField) bool {
+	return !(field.PkgPath == "" && unicode.IsUpper(rune(field.Name[0])))
+}
+
+// Convert a string like "--my-special-flag" to "MySpecialFlag".
+func titleCaseDashes(key string) string {
+	nextToUpper := true
+	mapFn := func(r rune) rune {
+		if r == '-' {
+			nextToUpper = true
+			return -1
+		}
+		if nextToUpper {
+			nextToUpper = false
+			return unicode.ToUpper(r)
+		}
+		return r
+	}
+	return strings.Map(mapFn, key)
+}
+
+// Best guess which field.Name in a struct to assign for an option key.
+func guessUntaggedField(key string) string {
+	switch {
+	case strings.HasPrefix(key, "--") && len(key[2:]) > 1:
+		return titleCaseDashes(key[2:])
+	case strings.HasPrefix(key, "-") && len(key[1:]) == 1:
+		return titleCaseDashes(key[1:])
+	case strings.HasPrefix(key, "<") && strings.HasSuffix(key, ">"):
+		key = key[1 : len(key)-1]
+	}
+	return strings.Title(strings.ToLower(key))
+}

+ 550 - 0
vendor/github.com/docopt/docopt-go/pattern.go

@@ -0,0 +1,550 @@
+package docopt
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+)
+
+type patternType uint
+
+const (
+	// leaf
+	patternArgument patternType = 1 << iota
+	patternCommand
+	patternOption
+
+	// branch
+	patternRequired
+	patternOptionAL
+	patternOptionSSHORTCUT // Marker/placeholder for [options] shortcut.
+	patternOneOrMore
+	patternEither
+
+	patternLeaf = patternArgument +
+		patternCommand +
+		patternOption
+	patternBranch = patternRequired +
+		patternOptionAL +
+		patternOptionSSHORTCUT +
+		patternOneOrMore +
+		patternEither
+	patternAll     = patternLeaf + patternBranch
+	patternDefault = 0
+)
+
+func (pt patternType) String() string {
+	switch pt {
+	case patternArgument:
+		return "argument"
+	case patternCommand:
+		return "command"
+	case patternOption:
+		return "option"
+	case patternRequired:
+		return "required"
+	case patternOptionAL:
+		return "optional"
+	case patternOptionSSHORTCUT:
+		return "optionsshortcut"
+	case patternOneOrMore:
+		return "oneormore"
+	case patternEither:
+		return "either"
+	case patternLeaf:
+		return "leaf"
+	case patternBranch:
+		return "branch"
+	case patternAll:
+		return "all"
+	case patternDefault:
+		return "default"
+	}
+	return ""
+}
+
+type pattern struct {
+	t patternType
+
+	children patternList
+
+	name  string
+	value interface{}
+
+	short    string
+	long     string
+	argcount int
+}
+
+type patternList []*pattern
+
+func newBranchPattern(t patternType, pl ...*pattern) *pattern {
+	var p pattern
+	p.t = t
+	p.children = make(patternList, len(pl))
+	copy(p.children, pl)
+	return &p
+}
+
+func newRequired(pl ...*pattern) *pattern {
+	return newBranchPattern(patternRequired, pl...)
+}
+
+func newEither(pl ...*pattern) *pattern {
+	return newBranchPattern(patternEither, pl...)
+}
+
+func newOneOrMore(pl ...*pattern) *pattern {
+	return newBranchPattern(patternOneOrMore, pl...)
+}
+
+func newOptional(pl ...*pattern) *pattern {
+	return newBranchPattern(patternOptionAL, pl...)
+}
+
+func newOptionsShortcut() *pattern {
+	var p pattern
+	p.t = patternOptionSSHORTCUT
+	return &p
+}
+
+func newLeafPattern(t patternType, name string, value interface{}) *pattern {
+	// default: value=nil
+	var p pattern
+	p.t = t
+	p.name = name
+	p.value = value
+	return &p
+}
+
+func newArgument(name string, value interface{}) *pattern {
+	// default: value=nil
+	return newLeafPattern(patternArgument, name, value)
+}
+
+func newCommand(name string, value interface{}) *pattern {
+	// default: value=false
+	var p pattern
+	p.t = patternCommand
+	p.name = name
+	p.value = value
+	return &p
+}
+
+func newOption(short, long string, argcount int, value interface{}) *pattern {
+	// default: "", "", 0, false
+	var p pattern
+	p.t = patternOption
+	p.short = short
+	p.long = long
+	if long != "" {
+		p.name = long
+	} else {
+		p.name = short
+	}
+	p.argcount = argcount
+	if value == false && argcount > 0 {
+		p.value = nil
+	} else {
+		p.value = value
+	}
+	return &p
+}
+
+func (p *pattern) flat(types patternType) (patternList, error) {
+	if p.t&patternLeaf != 0 {
+		if types == patternDefault {
+			types = patternAll
+		}
+		if p.t&types != 0 {
+			return patternList{p}, nil
+		}
+		return patternList{}, nil
+	}
+
+	if p.t&patternBranch != 0 {
+		if p.t&types != 0 {
+			return patternList{p}, nil
+		}
+		result := patternList{}
+		for _, child := range p.children {
+			childFlat, err := child.flat(types)
+			if err != nil {
+				return nil, err
+			}
+			result = append(result, childFlat...)
+		}
+		return result, nil
+	}
+	return nil, newError("unknown pattern type: %d, %d", p.t, types)
+}
+
+func (p *pattern) fix() error {
+	err := p.fixIdentities(nil)
+	if err != nil {
+		return err
+	}
+	p.fixRepeatingArguments()
+	return nil
+}
+
+func (p *pattern) fixIdentities(uniq patternList) error {
+	// Make pattern-tree tips point to same object if they are equal.
+	if p.t&patternBranch == 0 {
+		return nil
+	}
+	if uniq == nil {
+		pFlat, err := p.flat(patternDefault)
+		if err != nil {
+			return err
+		}
+		uniq = pFlat.unique()
+	}
+	for i, child := range p.children {
+		if child.t&patternBranch == 0 {
+			ind, err := uniq.index(child)
+			if err != nil {
+				return err
+			}
+			p.children[i] = uniq[ind]
+		} else {
+			err := child.fixIdentities(uniq)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	return nil
+}
+
+func (p *pattern) fixRepeatingArguments() {
+	// Fix elements that should accumulate/increment values.
+	var either []patternList
+
+	for _, child := range p.transform().children {
+		either = append(either, child.children)
+	}
+	for _, cas := range either {
+		casMultiple := patternList{}
+		for _, e := range cas {
+			if cas.count(e) > 1 {
+				casMultiple = append(casMultiple, e)
+			}
+		}
+		for _, e := range casMultiple {
+			if e.t == patternArgument || e.t == patternOption && e.argcount > 0 {
+				switch e.value.(type) {
+				case string:
+					e.value = strings.Fields(e.value.(string))
+				case []string:
+				default:
+					e.value = []string{}
+				}
+			}
+			if e.t == patternCommand || e.t == patternOption && e.argcount == 0 {
+				e.value = 0
+			}
+		}
+	}
+}
+
+func (p *pattern) match(left *patternList, collected *patternList) (bool, *patternList, *patternList) {
+	if collected == nil {
+		collected = &patternList{}
+	}
+	if p.t&patternRequired != 0 {
+		l := left
+		c := collected
+		for _, p := range p.children {
+			var matched bool
+			matched, l, c = p.match(l, c)
+			if !matched {
+				return false, left, collected
+			}
+		}
+		return true, l, c
+	} else if p.t&patternOptionAL != 0 || p.t&patternOptionSSHORTCUT != 0 {
+		for _, p := range p.children {
+			_, left, collected = p.match(left, collected)
+		}
+		return true, left, collected
+	} else if p.t&patternOneOrMore != 0 {
+		if len(p.children) != 1 {
+			panic("OneOrMore.match(): assert len(p.children) == 1")
+		}
+		l := left
+		c := collected
+		var lAlt *patternList
+		matched := true
+		times := 0
+		for matched {
+			// could it be that something didn't match but changed l or c?
+			matched, l, c = p.children[0].match(l, c)
+			if matched {
+				times++
+			}
+			if lAlt == l {
+				break
+			}
+			lAlt = l
+		}
+		if times >= 1 {
+			return true, l, c
+		}
+		return false, left, collected
+	} else if p.t&patternEither != 0 {
+		type outcomeStruct struct {
+			matched   bool
+			left      *patternList
+			collected *patternList
+			length    int
+		}
+		outcomes := []outcomeStruct{}
+		for _, p := range p.children {
+			matched, l, c := p.match(left, collected)
+			outcome := outcomeStruct{matched, l, c, len(*l)}
+			if matched {
+				outcomes = append(outcomes, outcome)
+			}
+		}
+		if len(outcomes) > 0 {
+			minLen := outcomes[0].length
+			minIndex := 0
+			for i, v := range outcomes {
+				if v.length < minLen {
+					minIndex = i
+				}
+			}
+			return outcomes[minIndex].matched, outcomes[minIndex].left, outcomes[minIndex].collected
+		}
+		return false, left, collected
+	} else if p.t&patternLeaf != 0 {
+		pos, match := p.singleMatch(left)
+		var increment interface{}
+		if match == nil {
+			return false, left, collected
+		}
+		leftAlt := make(patternList, len((*left)[:pos]), len((*left)[:pos])+len((*left)[pos+1:]))
+		copy(leftAlt, (*left)[:pos])
+		leftAlt = append(leftAlt, (*left)[pos+1:]...)
+		sameName := patternList{}
+		for _, a := range *collected {
+			if a.name == p.name {
+				sameName = append(sameName, a)
+			}
+		}
+
+		switch p.value.(type) {
+		case int, []string:
+			switch p.value.(type) {
+			case int:
+				increment = 1
+			case []string:
+				switch match.value.(type) {
+				case string:
+					increment = []string{match.value.(string)}
+				default:
+					increment = match.value
+				}
+			}
+			if len(sameName) == 0 {
+				match.value = increment
+				collectedMatch := make(patternList, len(*collected), len(*collected)+1)
+				copy(collectedMatch, *collected)
+				collectedMatch = append(collectedMatch, match)
+				return true, &leftAlt, &collectedMatch
+			}
+			switch sameName[0].value.(type) {
+			case int:
+				sameName[0].value = sameName[0].value.(int) + increment.(int)
+			case []string:
+				sameName[0].value = append(sameName[0].value.([]string), increment.([]string)...)
+			}
+			return true, &leftAlt, collected
+		}
+		collectedMatch := make(patternList, len(*collected), len(*collected)+1)
+		copy(collectedMatch, *collected)
+		collectedMatch = append(collectedMatch, match)
+		return true, &leftAlt, &collectedMatch
+	}
+	panic("unmatched type")
+}
+
+func (p *pattern) singleMatch(left *patternList) (int, *pattern) {
+	if p.t&patternArgument != 0 {
+		for n, pat := range *left {
+			if pat.t&patternArgument != 0 {
+				return n, newArgument(p.name, pat.value)
+			}
+		}
+		return -1, nil
+	} else if p.t&patternCommand != 0 {
+		for n, pat := range *left {
+			if pat.t&patternArgument != 0 {
+				if pat.value == p.name {
+					return n, newCommand(p.name, true)
+				}
+				break
+			}
+		}
+		return -1, nil
+	} else if p.t&patternOption != 0 {
+		for n, pat := range *left {
+			if p.name == pat.name {
+				return n, pat
+			}
+		}
+		return -1, nil
+	}
+	panic("unmatched type")
+}
+
+func (p *pattern) String() string {
+	if p.t&patternOption != 0 {
+		return fmt.Sprintf("%s(%s, %s, %d, %+v)", p.t, p.short, p.long, p.argcount, p.value)
+	} else if p.t&patternLeaf != 0 {
+		return fmt.Sprintf("%s(%s, %+v)", p.t, p.name, p.value)
+	} else if p.t&patternBranch != 0 {
+		result := ""
+		for i, child := range p.children {
+			if i > 0 {
+				result += ", "
+			}
+			result += child.String()
+		}
+		return fmt.Sprintf("%s(%s)", p.t, result)
+	}
+	panic("unmatched type")
+}
+
+func (p *pattern) transform() *pattern {
+	/*
+		Expand pattern into an (almost) equivalent one, but with single Either.
+
+		Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
+		Quirks: [-a] => (-a), (-a...) => (-a -a)
+	*/
+	result := []patternList{}
+	groups := []patternList{patternList{p}}
+	parents := patternRequired +
+		patternOptionAL +
+		patternOptionSSHORTCUT +
+		patternEither +
+		patternOneOrMore
+	for len(groups) > 0 {
+		children := groups[0]
+		groups = groups[1:]
+		var child *pattern
+		for _, c := range children {
+			if c.t&parents != 0 {
+				child = c
+				break
+			}
+		}
+		if child != nil {
+			children.remove(child)
+			if child.t&patternEither != 0 {
+				for _, c := range child.children {
+					r := patternList{}
+					r = append(r, c)
+					r = append(r, children...)
+					groups = append(groups, r)
+				}
+			} else if child.t&patternOneOrMore != 0 {
+				r := patternList{}
+				r = append(r, child.children.double()...)
+				r = append(r, children...)
+				groups = append(groups, r)
+			} else {
+				r := patternList{}
+				r = append(r, child.children...)
+				r = append(r, children...)
+				groups = append(groups, r)
+			}
+		} else {
+			result = append(result, children)
+		}
+	}
+	either := patternList{}
+	for _, e := range result {
+		either = append(either, newRequired(e...))
+	}
+	return newEither(either...)
+}
+
+func (p *pattern) eq(other *pattern) bool {
+	return reflect.DeepEqual(p, other)
+}
+
+func (pl patternList) unique() patternList {
+	table := make(map[string]bool)
+	result := patternList{}
+	for _, v := range pl {
+		if !table[v.String()] {
+			table[v.String()] = true
+			result = append(result, v)
+		}
+	}
+	return result
+}
+
+func (pl patternList) index(p *pattern) (int, error) {
+	for i, c := range pl {
+		if c.eq(p) {
+			return i, nil
+		}
+	}
+	return -1, newError("%s not in list", p)
+}
+
+func (pl patternList) count(p *pattern) int {
+	count := 0
+	for _, c := range pl {
+		if c.eq(p) {
+			count++
+		}
+	}
+	return count
+}
+
+func (pl patternList) diff(l patternList) patternList {
+	lAlt := make(patternList, len(l))
+	copy(lAlt, l)
+	result := make(patternList, 0, len(pl))
+	for _, v := range pl {
+		if v != nil {
+			match := false
+			for i, w := range lAlt {
+				if w.eq(v) {
+					match = true
+					lAlt[i] = nil
+					break
+				}
+			}
+			if match == false {
+				result = append(result, v)
+			}
+		}
+	}
+	return result
+}
+
+func (pl patternList) double() patternList {
+	l := len(pl)
+	result := make(patternList, l*2)
+	copy(result, pl)
+	copy(result[l:2*l], pl)
+	return result
+}
+
+func (pl *patternList) remove(p *pattern) {
+	(*pl) = pl.diff(patternList{p})
+}
+
+func (pl patternList) dictionary() map[string]interface{} {
+	dict := make(map[string]interface{})
+	for _, a := range pl {
+		dict[a.name] = a.value
+	}
+	return dict
+}

+ 9 - 0
vendor/github.com/docopt/docopt-go/test_golang.docopt

@@ -0,0 +1,9 @@
+r"""usage: prog [NAME_-2]..."""
+$ prog 10 20
+{"NAME_-2": ["10", "20"]}
+
+$ prog 10
+{"NAME_-2": ["10"]}
+
+$ prog
+{"NAME_-2": []}

+ 957 - 0
vendor/github.com/docopt/docopt-go/testcases.docopt

@@ -0,0 +1,957 @@
+r"""Usage: prog
+
+"""
+$ prog
+{}
+
+$ prog --xxx
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -a  All.
+
+"""
+$ prog
+{"-a": false}
+
+$ prog -a
+{"-a": true}
+
+$ prog -x
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: --all  All.
+
+"""
+$ prog
+{"--all": false}
+
+$ prog --all
+{"--all": true}
+
+$ prog --xxx
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -v, --verbose  Verbose.
+
+"""
+$ prog --verbose
+{"--verbose": true}
+
+$ prog --ver
+{"--verbose": true}
+
+$ prog -v
+{"--verbose": true}
+
+
+r"""Usage: prog [options]
+
+Options: -p PATH
+
+"""
+$ prog -p home/
+{"-p": "home/"}
+
+$ prog -phome/
+{"-p": "home/"}
+
+$ prog -p
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: --path <path>
+
+"""
+$ prog --path home/
+{"--path": "home/"}
+
+$ prog --path=home/
+{"--path": "home/"}
+
+$ prog --pa home/
+{"--path": "home/"}
+
+$ prog --pa=home/
+{"--path": "home/"}
+
+$ prog --path
+"user-error"
+
+
+r"""Usage: prog [options]
+
+Options: -p PATH, --path=<path>  Path to files.
+
+"""
+$ prog -proot
+{"--path": "root"}
+
+
+r"""Usage: prog [options]
+
+Options:    -p --path PATH  Path to files.
+
+"""
+$ prog -p root
+{"--path": "root"}
+
+$ prog --path root
+{"--path": "root"}
+
+
+r"""Usage: prog [options]
+
+Options:
+ -p PATH  Path to files [default: ./]
+
+"""
+$ prog
+{"-p": "./"}
+
+$ prog -phome
+{"-p": "home"}
+
+
+r"""UsAgE: prog [options]
+
+OpTiOnS: --path=<files>  Path to files
+                [dEfAuLt: /root]
+
+"""
+$ prog
+{"--path": "/root"}
+
+$ prog --path=home
+{"--path": "home"}
+
+
+r"""usage: prog [options]
+
+options:
+    -a        Add
+    -r        Remote
+    -m <msg>  Message
+
+"""
+$ prog -a -r -m Hello
+{"-a": true,
+ "-r": true,
+ "-m": "Hello"}
+
+$ prog -armyourass
+{"-a": true,
+ "-r": true,
+ "-m": "yourass"}
+
+$ prog -a -r
+{"-a": true,
+ "-r": true,
+ "-m": null}
+
+
+r"""Usage: prog [options]
+
+Options: --version
+         --verbose
+
+"""
+$ prog --version
+{"--version": true,
+ "--verbose": false}
+
+$ prog --verbose
+{"--version": false,
+ "--verbose": true}
+
+$ prog --ver
+"user-error"
+
+$ prog --verb
+{"--version": false,
+ "--verbose": true}
+
+
+r"""usage: prog [-a -r -m <msg>]
+
+options:
+ -a        Add
+ -r        Remote
+ -m <msg>  Message
+
+"""
+$ prog -armyourass
+{"-a": true,
+ "-r": true,
+ "-m": "yourass"}
+
+
+r"""usage: prog [-armmsg]
+
+options: -a        Add
+         -r        Remote
+         -m <msg>  Message
+
+"""
+$ prog -a -r -m Hello
+{"-a": true,
+ "-r": true,
+ "-m": "Hello"}
+
+
+r"""usage: prog -a -b
+
+options:
+ -a
+ -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog (-a -b)
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [-a] -b
+
+options: -a
+ -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog -b
+{"-a": false, "-b": true}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [(-a -b)]
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+{"-a": true, "-b": true}
+
+$ prog -b -a
+{"-a": true, "-b": true}
+
+$ prog -a
+"user-error"
+
+$ prog -b
+"user-error"
+
+$ prog
+{"-a": false, "-b": false}
+
+
+r"""usage: prog (-a|-b)
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+"user-error"
+
+$ prog
+"user-error"
+
+$ prog -a
+{"-a": true, "-b": false}
+
+$ prog -b
+{"-a": false, "-b": true}
+
+
+r"""usage: prog [ -a | -b ]
+
+options: -a
+         -b
+
+"""
+$ prog -a -b
+"user-error"
+
+$ prog
+{"-a": false, "-b": false}
+
+$ prog -a
+{"-a": true, "-b": false}
+
+$ prog -b
+{"-a": false, "-b": true}
+
+
+r"""usage: prog <arg>"""
+$ prog 10
+{"<arg>": "10"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<arg>]"""
+$ prog 10
+{"<arg>": "10"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+{"<arg>": null}
+
+
+r"""usage: prog <kind> <name> <type>"""
+$ prog 10 20 40
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
+
+$ prog 10 20
+"user-error"
+
+$ prog
+"user-error"
+
+
+r"""usage: prog <kind> [<name> <type>]"""
+$ prog 10 20 40
+{"<kind>": "10", "<name>": "20", "<type>": "40"}
+
+$ prog 10 20
+{"<kind>": "10", "<name>": "20", "<type>": null}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<kind> | <name> <type>]"""
+$ prog 10 20 40
+"user-error"
+
+$ prog 20 40
+{"<kind>": null, "<name>": "20", "<type>": "40"}
+
+$ prog
+{"<kind>": null, "<name>": null, "<type>": null}
+
+
+r"""usage: prog (<kind> --all | <name>)
+
+options:
+ --all
+
+"""
+$ prog 10 --all
+{"<kind>": "10", "--all": true, "<name>": null}
+
+$ prog 10
+{"<kind>": null, "--all": false, "<name>": "10"}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [<name> <name>]"""
+$ prog 10 20
+{"<name>": ["10", "20"]}
+
+$ prog 10
+{"<name>": ["10"]}
+
+$ prog
+{"<name>": []}
+
+
+r"""usage: prog [(<name> <name>)]"""
+$ prog 10 20
+{"<name>": ["10", "20"]}
+
+$ prog 10
+"user-error"
+
+$ prog
+{"<name>": []}
+
+
+r"""usage: prog NAME..."""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+"user-error"
+
+
+r"""usage: prog [NAME]..."""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog [NAME...]"""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog [NAME [NAME ...]]"""
+$ prog 10 20
+{"NAME": ["10", "20"]}
+
+$ prog 10
+{"NAME": ["10"]}
+
+$ prog
+{"NAME": []}
+
+
+r"""usage: prog (NAME | --foo NAME)
+
+options: --foo
+
+"""
+$ prog 10
+{"NAME": "10", "--foo": false}
+
+$ prog --foo 10
+{"NAME": "10", "--foo": true}
+
+$ prog --foo=10
+"user-error"
+
+
+r"""usage: prog (NAME | --foo) [--bar | NAME]
+
+options: --foo
+options: --bar
+
+"""
+$ prog 10
+{"NAME": ["10"], "--foo": false, "--bar": false}
+
+$ prog 10 20
+{"NAME": ["10", "20"], "--foo": false, "--bar": false}
+
+$ prog --foo --bar
+{"NAME": [], "--foo": true, "--bar": true}
+
+
+r"""Naval Fate.
+
+Usage:
+  prog ship new <name>...
+  prog ship [<name>] move <x> <y> [--speed=<kn>]
+  prog ship shoot <x> <y>
+  prog mine (set|remove) <x> <y> [--moored|--drifting]
+  prog -h | --help
+  prog --version
+
+Options:
+  -h --help     Show this screen.
+  --version     Show version.
+  --speed=<kn>  Speed in knots [default: 10].
+  --moored      Mored (anchored) mine.
+  --drifting    Drifting mine.
+
+"""
+$ prog ship Guardian move 150 300 --speed=20
+{"--drifting": false,
+ "--help": false,
+ "--moored": false,
+ "--speed": "20",
+ "--version": false,
+ "<name>": ["Guardian"],
+ "<x>": "150",
+ "<y>": "300",
+ "mine": false,
+ "move": true,
+ "new": false,
+ "remove": false,
+ "set": false,
+ "ship": true,
+ "shoot": false}
+
+
+r"""usage: prog --hello"""
+$ prog --hello
+{"--hello": true}
+
+
+r"""usage: prog [--hello=<world>]"""
+$ prog
+{"--hello": null}
+
+$ prog --hello wrld
+{"--hello": "wrld"}
+
+
+r"""usage: prog [-o]"""
+$ prog
+{"-o": false}
+
+$ prog -o
+{"-o": true}
+
+
+r"""usage: prog [-opr]"""
+$ prog -op
+{"-o": true, "-p": true, "-r": false}
+
+
+r"""usage: prog --aabb | --aa"""
+$ prog --aa
+{"--aabb": false, "--aa": true}
+
+$ prog --a
+"user-error"  # not a unique prefix
+
+#
+# Counting number of flags
+#
+
+r"""Usage: prog -v"""
+$ prog -v
+{"-v": true}
+
+
+r"""Usage: prog [-v -v]"""
+$ prog
+{"-v": 0}
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+
+r"""Usage: prog -v ..."""
+$ prog
+"user-error"
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+$ prog -vvvvvv
+{"-v": 6}
+
+
+r"""Usage: prog [-v | -vv | -vvv]
+
+This one is probably most readable user-friednly variant.
+
+"""
+$ prog
+{"-v": 0}
+
+$ prog -v
+{"-v": 1}
+
+$ prog -vv
+{"-v": 2}
+
+$ prog -vvvv
+"user-error"
+
+
+r"""usage: prog [--ver --ver]"""
+$ prog --ver --ver
+{"--ver": 2}
+
+
+#
+# Counting commands
+#
+
+r"""usage: prog [go]"""
+$ prog go
+{"go": true}
+
+
+r"""usage: prog [go go]"""
+$ prog
+{"go": 0}
+
+$ prog go
+{"go": 1}
+
+$ prog go go
+{"go": 2}
+
+$ prog go go go
+"user-error"