Browse Source

[vendor] update go-annex

cgars 8 years ago
parent
commit
e0a25b0a84
40 changed files with 4987 additions and 1 deletions
  1. 19 0
      vendor/github.com/G-Node/git-module/LICENSE
  2. 13 0
      vendor/github.com/G-Node/git-module/README.md
  3. 30 0
      vendor/github.com/G-Node/git-module/blob.go
  4. 158 0
      vendor/github.com/G-Node/git-module/command.go
  5. 310 0
      vendor/github.com/G-Node/git-module/commit.go
  6. 33 0
      vendor/github.com/G-Node/git-module/commit_archive.go
  7. 61 0
      vendor/github.com/G-Node/git-module/error.go
  8. 80 0
      vendor/github.com/G-Node/git-module/git.go
  9. 111 0
      vendor/github.com/G-Node/git-module/hook.go
  10. 295 0
      vendor/github.com/G-Node/git-module/repo.go
  11. 121 0
      vendor/github.com/G-Node/git-module/repo_branch.go
  12. 381 0
      vendor/github.com/G-Node/git-module/repo_commit.go
  13. 400 0
      vendor/github.com/G-Node/git-module/repo_diff.go
  14. 13 0
      vendor/github.com/G-Node/git-module/repo_hook.go
  15. 14 0
      vendor/github.com/G-Node/git-module/repo_object.go
  16. 81 0
      vendor/github.com/G-Node/git-module/repo_pull.go
  17. 209 0
      vendor/github.com/G-Node/git-module/repo_tag.go
  18. 26 0
      vendor/github.com/G-Node/git-module/repo_tree.go
  19. 93 0
      vendor/github.com/G-Node/git-module/sha1.go
  20. 48 0
      vendor/github.com/G-Node/git-module/signature.go
  21. 78 0
      vendor/github.com/G-Node/git-module/submodule.go
  22. 65 0
      vendor/github.com/G-Node/git-module/tag.go
  23. 149 0
      vendor/github.com/G-Node/git-module/tree.go
  24. 57 0
      vendor/github.com/G-Node/git-module/tree_blob.go
  25. 226 0
      vendor/github.com/G-Node/git-module/tree_entry.go
  26. 93 0
      vendor/github.com/G-Node/git-module/utils.go
  27. 29 0
      vendor/github.com/G-Node/go-annex/LICENSE
  28. 44 0
      vendor/github.com/G-Node/go-annex/add.go
  29. 58 0
      vendor/github.com/G-Node/go-annex/file.go
  30. 58 0
      vendor/github.com/G-Node/go-annex/file.go.orig
  31. 5 0
      vendor/github.com/G-Node/go-annex/util.go
  32. 24 0
      vendor/github.com/gopherjs/gopherjs/LICENSE
  33. 168 0
      vendor/github.com/gopherjs/gopherjs/js/js.go
  34. 35 0
      vendor/golang.org/x/crypto/bcrypt/base64.go
  35. 294 0
      vendor/golang.org/x/crypto/bcrypt/bcrypt.go
  36. 159 0
      vendor/golang.org/x/crypto/blowfish/block.go
  37. 91 0
      vendor/golang.org/x/crypto/blowfish/cipher.go
  38. 199 0
      vendor/golang.org/x/crypto/blowfish/const.go
  39. 31 1
      vendor/vendor.json
  40. 628 0
      vendor/vendor.json.orig

+ 19 - 0
vendor/github.com/G-Node/git-module/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2015 All Gogs Contributors
+
+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.

+ 13 - 0
vendor/github.com/G-Node/git-module/README.md

@@ -0,0 +1,13 @@
+# Git Module [![Build Status](https://travis-ci.org/gogits/git-module.svg?branch=master)](https://travis-ci.org/gogits/git-module)
+
+Package git-module is a Go module for Git access through shell commands.
+
+## Limitations
+
+- Go version must be at least **1.4**.
+- Git version must be no less than **1.7.1**, and greater than or equal to **1.8.3** is recommended.
+- For Windows users, try use as new a version as possible.
+
+## License
+
+This project is under the MIT License. See the [LICENSE](LICENSE) file for the full license text.

+ 30 - 0
vendor/github.com/G-Node/git-module/blob.go

@@ -0,0 +1,30 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"io"
+)
+
+// Blob represents a Git object.
+type Blob struct {
+	repo *Repository
+	*TreeEntry
+}
+
+// Data gets content of blob all at once and wrap it as io.Reader.
+// This can be very slow and memory consuming for huge content.
+func (b *Blob) Data() (io.Reader, error) {
+	stdout, err := NewCommand("show", b.ID.String()).RunInDirBytes(b.repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	return bytes.NewBuffer(stdout), nil
+}
+
+func (b *Blob) DataPipeline(stdout, stderr io.Writer) error {
+	return NewCommand("show", b.ID.String()).RunInDirPipeline(b.repo.Path, stdout, stderr)
+}

+ 158 - 0
vendor/github.com/G-Node/git-module/command.go

@@ -0,0 +1,158 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"strings"
+	"time"
+)
+
+// Command represents a command with its subcommands or arguments.
+type Command struct {
+	name string
+	args []string
+	envs []string
+}
+
+func (c *Command) String() string {
+	if len(c.args) == 0 {
+		return c.name
+	}
+	return fmt.Sprintf("%s %s", c.name, strings.Join(c.args, " "))
+}
+
+// NewCommand creates and returns a new Git Command based on given command and arguments.
+func NewCommand(args ...string) *Command {
+	return &Command{
+		name: "git",
+		args: args,
+	}
+}
+
+// NewCommand creates and returns a new Git Command based on given command and arguments.
+func NewACommand(args ...string) *Command {
+	return &Command{
+		name: "git-annex",
+		args: args,
+	}
+}
+
+// AddArguments adds new argument(s) to the command.
+func (c *Command) AddArguments(args ...string) *Command {
+	c.args = append(c.args, args...)
+	return c
+}
+
+// AddEnvs adds new environment variables to the command.
+func (c *Command) AddEnvs(envs ...string) *Command {
+	c.envs = append(c.envs, envs...)
+	return c
+}
+
+const DEFAULT_TIMEOUT = 60 * time.Second
+
+// RunInDirTimeoutPipeline executes the command in given directory with given timeout,
+// it pipes stdout and stderr to given io.Writer.
+func (c *Command) RunInDirTimeoutPipeline(timeout time.Duration, dir string, stdout, stderr io.Writer) error {
+	if timeout == -1 {
+		timeout = DEFAULT_TIMEOUT
+	}
+
+	if len(dir) == 0 {
+		log(c.String())
+	} else {
+		log("%s: %v", dir, c)
+	}
+
+	cmd := exec.Command(c.name, c.args...)
+	if c.envs != nil {
+		cmd.Env = append(os.Environ(), c.envs...)
+	}
+	cmd.Dir = dir
+	cmd.Stdout = stdout
+	cmd.Stderr = stderr
+	if err := cmd.Start(); err != nil {
+		return err
+	}
+
+	done := make(chan error)
+	go func() {
+		done <- cmd.Wait()
+	}()
+
+	var err error
+	select {
+	case <-time.After(timeout):
+		if cmd.Process != nil && cmd.ProcessState != nil && !cmd.ProcessState.Exited() {
+			if err := cmd.Process.Kill(); err != nil {
+				return fmt.Errorf("fail to kill process: %v", err)
+			}
+		}
+
+		<-done
+		return ErrExecTimeout{timeout}
+	case err = <-done:
+	}
+
+	return err
+}
+
+// RunInDirTimeout executes the command in given directory with given timeout,
+// and returns stdout in []byte and error (combined with stderr).
+func (c *Command) RunInDirTimeout(timeout time.Duration, dir string) ([]byte, error) {
+	stdout := new(bytes.Buffer)
+	stderr := new(bytes.Buffer)
+	if err := c.RunInDirTimeoutPipeline(timeout, dir, stdout, stderr); err != nil {
+		return nil, concatenateError(err, stderr.String())
+	}
+
+	if stdout.Len() > 0 {
+		log("stdout:\n%s", stdout.Bytes()[:1024])
+	}
+	return stdout.Bytes(), nil
+}
+
+// RunInDirPipeline executes the command in given directory,
+// it pipes stdout and stderr to given io.Writer.
+func (c *Command) RunInDirPipeline(dir string, stdout, stderr io.Writer) error {
+	return c.RunInDirTimeoutPipeline(-1, dir, stdout, stderr)
+}
+
+// RunInDir executes the command in given directory
+// and returns stdout in []byte and error (combined with stderr).
+func (c *Command) RunInDirBytes(dir string) ([]byte, error) {
+	return c.RunInDirTimeout(-1, dir)
+}
+
+// RunInDir executes the command in given directory
+// and returns stdout in string and error (combined with stderr).
+func (c *Command) RunInDir(dir string) (string, error) {
+	stdout, err := c.RunInDirTimeout(-1, dir)
+	if err != nil {
+		return "", err
+	}
+	return string(stdout), nil
+}
+
+// RunTimeout executes the command in defualt working directory with given timeout,
+// and returns stdout in string and error (combined with stderr).
+func (c *Command) RunTimeout(timeout time.Duration) (string, error) {
+	stdout, err := c.RunInDirTimeout(timeout, "")
+	if err != nil {
+		return "", err
+	}
+	return string(stdout), nil
+}
+
+// Run executes the command in defualt working directory
+// and returns stdout in string and error (combined with stderr).
+func (c *Command) Run() (string, error) {
+	return c.RunTimeout(-1)
+}

+ 310 - 0
vendor/github.com/G-Node/git-module/commit.go

@@ -0,0 +1,310 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bufio"
+	"bytes"
+	"container/list"
+	"fmt"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+
+	"github.com/mcuadros/go-version"
+)
+
+// Commit represents a git commit.
+type Commit struct {
+	Tree
+	ID            sha1 // The ID of this commit object
+	Author        *Signature
+	Committer     *Signature
+	CommitMessage string
+
+	parents        []sha1 // SHA1 strings
+	submoduleCache *objectCache
+}
+
+// Message returns the commit message. Same as retrieving CommitMessage directly.
+func (c *Commit) Message() string {
+	return c.CommitMessage
+}
+
+// Summary returns first line of commit message.
+func (c *Commit) Summary() string {
+	return strings.Split(c.CommitMessage, "\n")[0]
+}
+
+// ParentID returns oid of n-th parent (0-based index).
+// It returns nil if no such parent exists.
+func (c *Commit) ParentID(n int) (sha1, error) {
+	if n >= len(c.parents) {
+		return sha1{}, ErrNotExist{"", ""}
+	}
+	return c.parents[n], nil
+}
+
+// Parent returns n-th parent (0-based index) of the commit.
+func (c *Commit) Parent(n int) (*Commit, error) {
+	id, err := c.ParentID(n)
+	if err != nil {
+		return nil, err
+	}
+	parent, err := c.repo.getCommit(id)
+	if err != nil {
+		return nil, err
+	}
+	return parent, nil
+}
+
+// ParentCount returns number of parents of the commit.
+// 0 if this is the root commit,  otherwise 1,2, etc.
+func (c *Commit) ParentCount() int {
+	return len(c.parents)
+}
+
+func isImageFile(data []byte) (string, bool) {
+	contentType := http.DetectContentType(data)
+	if strings.Index(contentType, "image/") != -1 {
+		return contentType, true
+	}
+	return contentType, false
+}
+
+func (c *Commit) IsImageFile(name string) bool {
+	blob, err := c.GetBlobByPath(name)
+	if err != nil {
+		return false
+	}
+
+	dataRc, err := blob.Data()
+	if err != nil {
+		return false
+	}
+	buf := make([]byte, 1024)
+	n, _ := dataRc.Read(buf)
+	buf = buf[:n]
+	_, isImage := isImageFile(buf)
+	return isImage
+}
+
+// GetCommitByPath return the commit of relative path object.
+func (c *Commit) GetCommitByPath(relpath string) (*Commit, error) {
+	return c.repo.getCommitByPathWithID(c.ID, relpath)
+}
+
+// AddAllChanges marks local changes to be ready for commit.
+func AddChanges(repoPath string, all bool, files ...string) error {
+	cmd := NewCommand("add")
+	if all {
+		cmd.AddArguments("--all")
+	}
+	_, err := cmd.AddArguments(files...).RunInDir(repoPath)
+	return err
+}
+
+type CommitChangesOptions struct {
+	Committer *Signature
+	Author    *Signature
+	Message   string
+}
+
+// CommitChanges commits local changes with given committer, author and message.
+// If author is nil, it will be the same as committer.
+func CommitChanges(repoPath string, opts CommitChangesOptions) error {
+	cmd := NewCommand()
+	if opts.Committer != nil {
+		cmd.AddEnvs("GIT_COMMITTER_NAME="+opts.Committer.Name, "GIT_COMMITTER_EMAIL="+opts.Committer.Email)
+	}
+	cmd.AddArguments("commit")
+
+	if opts.Author == nil {
+		opts.Author = opts.Committer
+	}
+	if opts.Author != nil {
+		cmd.AddArguments(fmt.Sprintf("--author='%s <%s>'", opts.Author.Name, opts.Author.Email))
+	}
+	cmd.AddArguments("-m", opts.Message)
+
+	_, err := cmd.RunInDir(repoPath)
+	// No stderr but exit status 1 means nothing to commit.
+	if err != nil && err.Error() == "exit status 1" {
+		return nil
+	}
+	return err
+}
+
+func commitsCount(repoPath, revision, relpath string) (int64, error) {
+	var cmd *Command
+	isFallback := false
+	if version.Compare(gitVersion, "1.8.0", "<") {
+		isFallback = true
+		cmd = NewCommand("log", "--pretty=format:''")
+	} else {
+		cmd = NewCommand("rev-list", "--count")
+	}
+	cmd.AddArguments(revision)
+	if len(relpath) > 0 {
+		cmd.AddArguments("--", relpath)
+	}
+
+	stdout, err := cmd.RunInDir(repoPath)
+	if err != nil {
+		return 0, err
+	}
+
+	if isFallback {
+		return int64(strings.Count(stdout, "\n")) + 1, nil
+	}
+	return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
+}
+
+// CommitsCount returns number of total commits of until given revision.
+func CommitsCount(repoPath, revision string) (int64, error) {
+	return commitsCount(repoPath, revision, "")
+}
+
+func (c *Commit) CommitsCount() (int64, error) {
+	return CommitsCount(c.repo.Path, c.ID.String())
+}
+
+func (c *Commit) CommitsByRangeSize(page, size int) (*list.List, error) {
+	return c.repo.CommitsByRangeSize(c.ID.String(), page, size)
+}
+
+func (c *Commit) CommitsByRange(page int) (*list.List, error) {
+	return c.repo.CommitsByRange(c.ID.String(), page)
+}
+
+func (c *Commit) CommitsBefore() (*list.List, error) {
+	return c.repo.getCommitsBefore(c.ID)
+}
+
+func (c *Commit) CommitsBeforeLimit(num int) (*list.List, error) {
+	return c.repo.getCommitsBeforeLimit(c.ID, num)
+}
+
+func (c *Commit) CommitsBeforeUntil(commitID string) (*list.List, error) {
+	endCommit, err := c.repo.GetCommit(commitID)
+	if err != nil {
+		return nil, err
+	}
+	return c.repo.CommitsBetween(c, endCommit)
+}
+
+func (c *Commit) SearchCommits(keyword string) (*list.List, error) {
+	return c.repo.searchCommits(c.ID, keyword)
+}
+
+func (c *Commit) GetFilesChangedSinceCommit(pastCommit string) ([]string, error) {
+	return c.repo.getFilesChanged(pastCommit, c.ID.String())
+}
+
+func (c *Commit) GetSubModules() (*objectCache, error) {
+	if c.submoduleCache != nil {
+		return c.submoduleCache, nil
+	}
+
+	entry, err := c.GetTreeEntryByPath(".gitmodules")
+	if err != nil {
+		return nil, err
+	}
+	rd, err := entry.Blob().Data()
+	if err != nil {
+		return nil, err
+	}
+
+	scanner := bufio.NewScanner(rd)
+	c.submoduleCache = newObjectCache()
+	var ismodule bool
+	var path string
+	for scanner.Scan() {
+		if strings.HasPrefix(scanner.Text(), "[submodule") {
+			ismodule = true
+			continue
+		}
+		if ismodule {
+			fields := strings.Split(scanner.Text(), "=")
+			k := strings.TrimSpace(fields[0])
+			if k == "path" {
+				path = strings.TrimSpace(fields[1])
+			} else if k == "url" {
+				c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])})
+				ismodule = false
+			}
+		}
+	}
+
+	return c.submoduleCache, nil
+}
+
+func (c *Commit) GetSubModule(entryname string) (*SubModule, error) {
+	modules, err := c.GetSubModules()
+	if err != nil {
+		return nil, err
+	}
+
+	module, has := modules.Get(entryname)
+	if has {
+		return module.(*SubModule), nil
+	}
+	return nil, nil
+}
+
+// CommitFileStatus represents status of files in a commit.
+type CommitFileStatus struct {
+	Added    []string
+	Removed  []string
+	Modified []string
+}
+
+func NewCommitFileStatus() *CommitFileStatus {
+	return &CommitFileStatus{
+		[]string{}, []string{}, []string{},
+	}
+}
+
+// GetCommitFileStatus returns file status of commit in given repository.
+func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) {
+	stdout, w := io.Pipe()
+	done := make(chan struct{})
+	fileStatus := NewCommitFileStatus()
+	go func() {
+		scanner := bufio.NewScanner(stdout)
+		for scanner.Scan() {
+			fields := strings.Fields(scanner.Text())
+			if len(fields) < 2 {
+				continue
+			}
+
+			switch fields[0][0] {
+			case 'A':
+				fileStatus.Added = append(fileStatus.Added, fields[1])
+			case 'D':
+				fileStatus.Removed = append(fileStatus.Removed, fields[1])
+			case 'M':
+				fileStatus.Modified = append(fileStatus.Modified, fields[1])
+			}
+		}
+		done <- struct{}{}
+	}()
+
+	stderr := new(bytes.Buffer)
+	err := NewCommand("log", "-1", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr)
+	w.Close() // Close writer to exit parsing goroutine
+	if err != nil {
+		return nil, concatenateError(err, stderr.String())
+	}
+
+	<-done
+	return fileStatus, nil
+}
+
+// FileStatus returns file status of commit.
+func (c *Commit) FileStatus() (*CommitFileStatus, error) {
+	return GetCommitFileStatus(c.repo.Path, c.ID.String())
+}

+ 33 - 0
vendor/github.com/G-Node/git-module/commit_archive.go

@@ -0,0 +1,33 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+)
+
+type ArchiveType int
+
+const (
+	ZIP ArchiveType = iota + 1
+	TARGZ
+)
+
+func (c *Commit) CreateArchive(target string, archiveType ArchiveType) error {
+	var format string
+	switch archiveType {
+	case ZIP:
+		format = "zip"
+	case TARGZ:
+		format = "tar.gz"
+	default:
+		return fmt.Errorf("unknown format: %v", archiveType)
+	}
+
+	_, err := NewCommand("archive", "--prefix="+filepath.Base(strings.TrimSuffix(c.repo.Path, ".git"))+"/", "--format="+format, "-o", target, c.ID.String()).RunInDir(c.repo.Path)
+	return err
+}

+ 61 - 0
vendor/github.com/G-Node/git-module/error.go

@@ -0,0 +1,61 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"time"
+)
+
+type ErrExecTimeout struct {
+	Duration time.Duration
+}
+
+func IsErrExecTimeout(err error) bool {
+	_, ok := err.(ErrExecTimeout)
+	return ok
+}
+
+func (err ErrExecTimeout) Error() string {
+	return fmt.Sprintf("execution is timeout [duration: %v]", err.Duration)
+}
+
+type ErrNotExist struct {
+	ID      string
+	RelPath string
+}
+
+func IsErrNotExist(err error) bool {
+	_, ok := err.(ErrNotExist)
+	return ok
+}
+
+func (err ErrNotExist) Error() string {
+	return fmt.Sprintf("object does not exist [id: %s, rel_path: %s]", err.ID, err.RelPath)
+}
+
+type ErrUnsupportedVersion struct {
+	Required string
+}
+
+func IsErrUnsupportedVersion(err error) bool {
+	_, ok := err.(ErrUnsupportedVersion)
+	return ok
+}
+
+func (err ErrUnsupportedVersion) Error() string {
+	return fmt.Sprintf("Operation requires higher version [required: %s]", err.Required)
+}
+
+type ErrNoMergeBase struct{}
+
+func IsErrNoMergeBase(err error) bool {
+	_, ok := err.(ErrNoMergeBase)
+	return ok
+}
+
+func (err ErrNoMergeBase) Error() string {
+	return "no merge based found"
+}

+ 80 - 0
vendor/github.com/G-Node/git-module/git.go

@@ -0,0 +1,80 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"strings"
+	"time"
+)
+
+const _VERSION = "0.6.3"
+
+func Version() string {
+	return _VERSION
+}
+
+var (
+	// Debug enables verbose logging on everything.
+	// This should be false in case Gogs starts in SSH mode.
+	Debug  = false
+	Prefix = "[git-module] "
+)
+
+func log(format string, args ...interface{}) {
+	if !Debug {
+		return
+	}
+
+	fmt.Print(Prefix)
+	if len(args) == 0 {
+		fmt.Println(format)
+	} else {
+		fmt.Printf(format+"\n", args...)
+	}
+}
+
+var gitVersion string
+
+// Version returns current Git version from shell.
+func BinVersion() (string, error) {
+	if len(gitVersion) > 0 {
+		return gitVersion, nil
+	}
+
+	stdout, err := NewCommand("version").Run()
+	if err != nil {
+		return "", err
+	}
+
+	fields := strings.Fields(stdout)
+	if len(fields) < 3 {
+		return "", fmt.Errorf("not enough output: %s", stdout)
+	}
+
+	// Handle special case on Windows.
+	i := strings.Index(fields[2], "windows")
+	if i >= 1 {
+		gitVersion = fields[2][:i-1]
+		return gitVersion, nil
+	}
+
+	gitVersion = fields[2]
+	return gitVersion, nil
+}
+
+func init() {
+	BinVersion()
+}
+
+// Fsck verifies the connectivity and validity of the objects in the database
+func Fsck(repoPath string, timeout time.Duration, args ...string) error {
+	// Make sure timeout makes sense.
+	if timeout <= 0 {
+		timeout = -1
+	}
+	_, err := NewCommand("fsck").AddArguments(args...).RunInDirTimeout(timeout, repoPath)
+	return err
+}

+ 111 - 0
vendor/github.com/G-Node/git-module/hook.go

@@ -0,0 +1,111 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"path"
+	"strings"
+)
+
+var (
+	// Direcotry of hook and sample files. Can be changed to "custom_hooks" for very purpose.
+	HookDir       = "hooks"
+	HookSampleDir = HookDir
+	// HookNames is a list of Git server hooks' name that are supported.
+	HookNames = []string{
+		"pre-receive",
+		"update",
+		"post-receive",
+	}
+)
+
+var (
+	ErrNotValidHook = errors.New("not a valid Git hook")
+)
+
+// IsValidHookName returns true if given name is a valid Git hook.
+func IsValidHookName(name string) bool {
+	for _, hn := range HookNames {
+		if hn == name {
+			return true
+		}
+	}
+	return false
+}
+
+// Hook represents a Git hook.
+type Hook struct {
+	name     string
+	IsActive bool   // Indicates whether repository has this hook.
+	Content  string // Content of hook if it's active.
+	Sample   string // Sample content from Git.
+	path     string // Hook file path.
+}
+
+// GetHook returns a Git hook by given name and repository.
+func GetHook(repoPath, name string) (*Hook, error) {
+	if !IsValidHookName(name) {
+		return nil, ErrNotValidHook
+	}
+	h := &Hook{
+		name: name,
+		path: path.Join(repoPath, HookDir, name),
+	}
+	if isFile(h.path) {
+		data, err := ioutil.ReadFile(h.path)
+		if err != nil {
+			return nil, err
+		}
+		h.IsActive = true
+		h.Content = string(data)
+		return h, nil
+	}
+
+	// Check sample file
+	samplePath := path.Join(repoPath, HookSampleDir, h.name) + ".sample"
+	if isFile(samplePath) {
+		data, err := ioutil.ReadFile(samplePath)
+		if err != nil {
+			return nil, err
+		}
+		h.Sample = string(data)
+	}
+	return h, nil
+}
+
+func (h *Hook) Name() string {
+	return h.name
+}
+
+// Update updates content hook file.
+func (h *Hook) Update() error {
+	if len(strings.TrimSpace(h.Content)) == 0 {
+		if isExist(h.path) {
+			return os.Remove(h.path)
+		}
+		return nil
+	}
+	os.MkdirAll(path.Dir(h.path), os.ModePerm)
+	return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm)
+}
+
+// ListHooks returns a list of Git hooks of given repository.
+func ListHooks(repoPath string) (_ []*Hook, err error) {
+	if !isDir(path.Join(repoPath, "hooks")) {
+		return nil, errors.New("hooks path does not exist")
+	}
+
+	hooks := make([]*Hook, len(HookNames))
+	for i, name := range HookNames {
+		hooks[i], err = GetHook(repoPath, name)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return hooks, nil
+}

+ 295 - 0
vendor/github.com/G-Node/git-module/repo.go

@@ -0,0 +1,295 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"container/list"
+	"errors"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"time"
+
+	"github.com/Unknwon/com"
+)
+
+// Repository represents a Git repository.
+type Repository struct {
+	Path string
+
+	commitCache *objectCache
+	tagCache    *objectCache
+}
+
+const _PRETTY_LOG_FORMAT = `--pretty=format:%H`
+
+func (repo *Repository) parsePrettyFormatLogToList(logs []byte) (*list.List, error) {
+	l := list.New()
+	if len(logs) == 0 {
+		return l, nil
+	}
+
+	parts := bytes.Split(logs, []byte{'\n'})
+
+	for _, commitId := range parts {
+		commit, err := repo.GetCommit(string(commitId))
+		if err != nil {
+			return nil, err
+		}
+		l.PushBack(commit)
+	}
+
+	return l, nil
+}
+
+type NetworkOptions struct {
+	URL     string
+	Timeout time.Duration
+}
+
+// IsRepoURLAccessible checks if given repository URL is accessible.
+func IsRepoURLAccessible(opts NetworkOptions) bool {
+	cmd := NewCommand("ls-remote", "-q", "-h", opts.URL, "HEAD")
+	if opts.Timeout <= 0 {
+		opts.Timeout = -1
+	}
+	_, err := cmd.RunTimeout(opts.Timeout)
+	if err != nil {
+		return false
+	}
+	return true
+}
+
+// InitRepository initializes a new Git repository.
+func InitRepository(repoPath string, bare bool) error {
+	os.MkdirAll(repoPath, os.ModePerm)
+
+	cmd := NewCommand("init")
+	if bare {
+		cmd.AddArguments("--bare")
+	}
+	_, err := cmd.RunInDir(repoPath)
+	return err
+}
+
+// OpenRepository opens the repository at the given path.
+func OpenRepository(repoPath string) (*Repository, error) {
+	repoPath, err := filepath.Abs(repoPath)
+	if err != nil {
+		return nil, err
+	} else if !isDir(repoPath) {
+		return nil, errors.New("no such file or directory")
+	}
+
+	return &Repository{
+		Path:        repoPath,
+		commitCache: newObjectCache(),
+		tagCache:    newObjectCache(),
+	}, nil
+}
+
+type CloneRepoOptions struct {
+	Mirror  bool
+	Bare    bool
+	Quiet   bool
+	Branch  string
+	Timeout time.Duration
+}
+
+// Clone clones original repository to target path.
+func Clone(from, to string, opts CloneRepoOptions) (err error) {
+	toDir := path.Dir(to)
+	if err = os.MkdirAll(toDir, os.ModePerm); err != nil {
+		return err
+	}
+
+	cmd := NewCommand("clone")
+	if opts.Mirror {
+		cmd.AddArguments("--mirror")
+	}
+	if opts.Bare {
+		cmd.AddArguments("--bare")
+	}
+	if opts.Quiet {
+		cmd.AddArguments("--quiet")
+	}
+	if len(opts.Branch) > 0 {
+		cmd.AddArguments("-b", opts.Branch)
+	}
+	cmd.AddArguments(from, to)
+
+	if opts.Timeout <= 0 {
+		opts.Timeout = -1
+	}
+	_, err = cmd.RunTimeout(opts.Timeout)
+	return err
+}
+
+type FetchRemoteOptions struct {
+	Prune   bool
+	Timeout time.Duration
+}
+
+// Fetch fetches changes from remotes without merging.
+func Fetch(repoPath string, opts FetchRemoteOptions) error {
+	cmd := NewCommand("fetch")
+	if opts.Prune {
+		cmd.AddArguments("--prune")
+	}
+
+	if opts.Timeout <= 0 {
+		opts.Timeout = -1
+	}
+	_, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
+	return err
+}
+
+type PullRemoteOptions struct {
+	All     bool
+	Rebase  bool
+	Remote  string
+	Branch  string
+	Timeout time.Duration
+}
+
+// Pull pulls changes from remotes.
+func Pull(repoPath string, opts PullRemoteOptions) error {
+	cmd := NewCommand("pull")
+	if opts.Rebase {
+		cmd.AddArguments("--rebase")
+	}
+	if opts.All {
+		cmd.AddArguments("--all")
+	} else {
+		cmd.AddArguments(opts.Remote)
+		cmd.AddArguments(opts.Branch)
+	}
+
+	if opts.Timeout <= 0 {
+		opts.Timeout = -1
+	}
+	_, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
+	return err
+}
+
+// Push pushs local commits to given remote branch.
+func Push(repoPath, remote, branch string) error {
+	_, err := NewCommand("push", remote, branch).RunInDir(repoPath)
+	return err
+}
+
+type CheckoutOptions struct {
+	Branch    string
+	OldBranch string
+	Timeout   time.Duration
+}
+
+// Checkout checkouts a branch
+func Checkout(repoPath string, opts CheckoutOptions) error {
+	cmd := NewCommand("checkout")
+	if len(opts.OldBranch) > 0 {
+		cmd.AddArguments("-b")
+	}
+
+	cmd.AddArguments(opts.Branch)
+
+	if len(opts.OldBranch) > 0 {
+		cmd.AddArguments(opts.OldBranch)
+	}
+	if opts.Timeout <= 0 {
+		opts.Timeout = -1
+	}
+	_, err := cmd.RunInDirTimeout(opts.Timeout, repoPath)
+	return err
+}
+
+// ResetHEAD resets HEAD to given revision or head of branch.
+func ResetHEAD(repoPath string, hard bool, revision string) error {
+	cmd := NewCommand("reset")
+	if hard {
+		cmd.AddArguments("--hard")
+	}
+	_, err := cmd.AddArguments(revision).RunInDir(repoPath)
+	return err
+}
+
+// MoveFile moves a file to another file or directory.
+func MoveFile(repoPath, oldTreeName, newTreeName string) error {
+	_, err := NewCommand("mv").AddArguments(oldTreeName, newTreeName).RunInDir(repoPath)
+	return err
+}
+
+// CountObject represents disk usage report of Git repository.
+type CountObject struct {
+	Count         int64
+	Size          int64
+	InPack        int64
+	Packs         int64
+	SizePack      int64
+	PrunePackable int64
+	Garbage       int64
+	SizeGarbage   int64
+}
+
+const (
+	_STAT_COUNT          = "count: "
+	_STAT_SIZE           = "size: "
+	_STAT_IN_PACK        = "in-pack: "
+	_STAT_PACKS          = "packs: "
+	_STAT_SIZE_PACK      = "size-pack: "
+	_STAT_PRUNE_PACKABLE = "prune-packable: "
+	_STAT_GARBAGE        = "garbage: "
+	_STAT_SIZE_GARBAGE   = "size-garbage: "
+)
+
+// GetRepoSize returns disk usage report of repository in given path.
+func GetRepoSize(repoPath string) (*CountObject, error) {
+	cmd := NewCommand("count-objects", "-v")
+	stdout, err := cmd.RunInDir(repoPath)
+	if err != nil {
+		return nil, err
+	}
+
+	countObject := new(CountObject)
+	for _, line := range strings.Split(stdout, "\n") {
+		switch {
+		case strings.HasPrefix(line, _STAT_COUNT):
+			countObject.Count = com.StrTo(line[7:]).MustInt64()
+		case strings.HasPrefix(line, _STAT_SIZE):
+			countObject.Size = com.StrTo(line[6:]).MustInt64() * 1024
+		case strings.HasPrefix(line, _STAT_IN_PACK):
+			countObject.InPack = com.StrTo(line[9:]).MustInt64()
+		case strings.HasPrefix(line, _STAT_PACKS):
+			countObject.Packs = com.StrTo(line[7:]).MustInt64()
+		case strings.HasPrefix(line, _STAT_SIZE_PACK):
+			countObject.SizePack = com.StrTo(line[11:]).MustInt64() * 1024
+		case strings.HasPrefix(line, _STAT_PRUNE_PACKABLE):
+			countObject.PrunePackable = com.StrTo(line[16:]).MustInt64()
+		case strings.HasPrefix(line, _STAT_GARBAGE):
+			countObject.Garbage = com.StrTo(line[9:]).MustInt64()
+		case strings.HasPrefix(line, _STAT_SIZE_GARBAGE):
+			countObject.SizeGarbage = com.StrTo(line[14:]).MustInt64() * 1024
+		}
+	}
+
+	return countObject, nil
+}
+
+// GetLatestCommitDate returns the date of latest commit of repository.
+// If branch is empty, it returns the latest commit across all branches.
+func GetLatestCommitDate(repoPath, branch string) (time.Time, error) {
+	cmd := NewCommand("for-each-ref", "--count=1", "--sort=-committerdate", "--format=%(committerdate:iso8601)")
+	if len(branch) > 0 {
+		cmd.AddArguments("refs/heads/" + branch)
+	}
+	stdout, err := cmd.RunInDir(repoPath)
+	if err != nil {
+		return time.Time{}, err
+	}
+
+	return time.Parse("2006-01-02 15:04:05 -0700", strings.TrimSpace(stdout))
+}

+ 121 - 0
vendor/github.com/G-Node/git-module/repo_branch.go

@@ -0,0 +1,121 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/mcuadros/go-version"
+)
+
+const BRANCH_PREFIX = "refs/heads/"
+
+// IsReferenceExist returns true if given reference exists in the repository.
+func IsReferenceExist(repoPath, name string) bool {
+	_, err := NewCommand("show-ref", "--verify", name).RunInDir(repoPath)
+	return err == nil
+}
+
+// IsBranchExist returns true if given branch exists in the repository.
+func IsBranchExist(repoPath, name string) bool {
+	return IsReferenceExist(repoPath, BRANCH_PREFIX+name)
+}
+
+func (repo *Repository) IsBranchExist(name string) bool {
+	return IsBranchExist(repo.Path, name)
+}
+
+// Branch represents a Git branch.
+type Branch struct {
+	Name string
+	Path string
+}
+
+// GetHEADBranch returns corresponding branch of HEAD.
+func (repo *Repository) GetHEADBranch() (*Branch, error) {
+	stdout, err := NewCommand("symbolic-ref", "HEAD").RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	stdout = strings.TrimSpace(stdout)
+
+	if !strings.HasPrefix(stdout, BRANCH_PREFIX) {
+		return nil, fmt.Errorf("invalid HEAD branch: %v", stdout)
+	}
+
+	return &Branch{
+		Name: stdout[len(BRANCH_PREFIX):],
+		Path: stdout,
+	}, nil
+}
+
+// SetDefaultBranch sets default branch of repository.
+func (repo *Repository) SetDefaultBranch(name string) error {
+	if version.Compare(gitVersion, "1.7.10", "<") {
+		return ErrUnsupportedVersion{"1.7.10"}
+	}
+
+	_, err := NewCommand("symbolic-ref", "HEAD", BRANCH_PREFIX+name).RunInDir(repo.Path)
+	return err
+}
+
+// GetBranches returns all branches of the repository.
+func (repo *Repository) GetBranches() ([]string, error) {
+	stdout, err := NewCommand("show-ref", "--heads").RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	infos := strings.Split(stdout, "\n")
+	branches := make([]string, len(infos)-1)
+	for i, info := range infos[:len(infos)-1] {
+		fields := strings.Fields(info)
+		if len(fields) != 2 {
+			continue // NOTE: I should believe git will not give me wrong string.
+		}
+		branches[i] = strings.TrimPrefix(fields[1], BRANCH_PREFIX)
+	}
+	return branches, nil
+}
+
+// Option(s) for delete branch
+type DeleteBranchOptions struct {
+	Force bool
+}
+
+// DeleteBranch delete a branch by name on repository.
+func (repo *Repository) DeleteBranch(name string, opts DeleteBranchOptions) error {
+	cmd := NewCommand("branch")
+
+	if opts.Force {
+		cmd.AddArguments("-D")
+	} else {
+		cmd.AddArguments("-d")
+	}
+
+	cmd.AddArguments(name)
+	_, err := cmd.RunInDir(repo.Path)
+
+	return err
+}
+
+// AddRemote adds a new remote to repository.
+func (repo *Repository) AddRemote(name, url string, fetch bool) error {
+	cmd := NewCommand("remote", "add")
+	if fetch {
+		cmd.AddArguments("-f")
+	}
+	cmd.AddArguments(name, url)
+
+	_, err := cmd.RunInDir(repo.Path)
+	return err
+}
+
+// RemoveRemote removes a remote from repository.
+func (repo *Repository) RemoveRemote(name string) error {
+	_, err := NewCommand("remote", "remove", name).RunInDir(repo.Path)
+	return err
+}

+ 381 - 0
vendor/github.com/G-Node/git-module/repo_commit.go

@@ -0,0 +1,381 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"container/list"
+	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/mcuadros/go-version"
+)
+
+const REMOTE_PREFIX = "refs/remotes/"
+
+// getRefCommitID returns the last commit ID string of given reference (branch or tag).
+func (repo *Repository) getRefCommitID(name string) (string, error) {
+	stdout, err := NewCommand("show-ref", "--verify", name).RunInDir(repo.Path)
+	if err != nil {
+		if strings.Contains(err.Error(), "not a valid ref") {
+			return "", ErrNotExist{name, ""}
+		}
+		return "", err
+	}
+	return strings.Split(stdout, " ")[0], nil
+}
+
+// GetBranchCommitID returns last commit ID string of given branch.
+func (repo *Repository) GetBranchCommitID(name string) (string, error) {
+	return repo.getRefCommitID(BRANCH_PREFIX + name)
+}
+
+// GetTagCommitID returns last commit ID string of given tag.
+func (repo *Repository) GetTagCommitID(name string) (string, error) {
+	return repo.getRefCommitID(TAG_PREFIX + name)
+}
+
+// GetRemoteBranchCommitID returns last commit ID string of given remote branch.
+func (repo *Repository) GetRemoteBranchCommitID(name string) (string, error) {
+	return repo.getRefCommitID(REMOTE_PREFIX + name)
+}
+
+// parseCommitData parses commit information from the (uncompressed) raw
+// data from the commit object.
+// \n\n separate headers from message
+func parseCommitData(data []byte) (*Commit, error) {
+	commit := new(Commit)
+	commit.parents = make([]sha1, 0, 1)
+	// we now have the contents of the commit object. Let's investigate...
+	nextline := 0
+l:
+	for {
+		eol := bytes.IndexByte(data[nextline:], '\n')
+		switch {
+		case eol > 0:
+			line := data[nextline : nextline+eol]
+			spacepos := bytes.IndexByte(line, ' ')
+			reftype := line[:spacepos]
+			switch string(reftype) {
+			case "tree", "object":
+				id, err := NewIDFromString(string(line[spacepos+1:]))
+				if err != nil {
+					return nil, err
+				}
+				commit.Tree.ID = id
+			case "parent":
+				// A commit can have one or more parents
+				oid, err := NewIDFromString(string(line[spacepos+1:]))
+				if err != nil {
+					return nil, err
+				}
+				commit.parents = append(commit.parents, oid)
+			case "author", "tagger":
+				sig, err := newSignatureFromCommitline(line[spacepos+1:])
+				if err != nil {
+					return nil, err
+				}
+				commit.Author = sig
+			case "committer":
+				sig, err := newSignatureFromCommitline(line[spacepos+1:])
+				if err != nil {
+					return nil, err
+				}
+				commit.Committer = sig
+			}
+			nextline += eol + 1
+		case eol == 0:
+			commit.CommitMessage = string(data[nextline+1:])
+			break l
+		default:
+			break l
+		}
+	}
+	return commit, nil
+}
+
+func (repo *Repository) getCommit(id sha1) (*Commit, error) {
+	c, ok := repo.commitCache.Get(id.String())
+	if ok {
+		log("Hit cache: %s", id)
+		return c.(*Commit), nil
+	}
+
+	data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path)
+	if err != nil {
+		if strings.Contains(err.Error(), "exit status 128") {
+			return nil, ErrNotExist{id.String(), ""}
+		}
+		return nil, err
+	}
+
+	commit, err := parseCommitData(data)
+	if err != nil {
+		return nil, err
+	}
+	commit.repo = repo
+	commit.ID = id
+
+	repo.commitCache.Set(id.String(), commit)
+	return commit, nil
+}
+
+// GetCommit returns commit object of by ID string.
+func (repo *Repository) GetCommit(commitID string) (*Commit, error) {
+	if len(commitID) != 40 {
+		var err error
+		commitID, err = NewCommand("rev-parse", commitID).RunInDir(repo.Path)
+		if err != nil {
+			if strings.Contains(err.Error(), "exit status 128") {
+				return nil, ErrNotExist{commitID, ""}
+			}
+			return nil, err
+		}
+	}
+	id, err := NewIDFromString(commitID)
+	if err != nil {
+		return nil, err
+	}
+
+	return repo.getCommit(id)
+}
+
+// GetBranchCommit returns the last commit of given branch.
+func (repo *Repository) GetBranchCommit(name string) (*Commit, error) {
+	commitID, err := repo.GetBranchCommitID(name)
+	if err != nil {
+		return nil, err
+	}
+	return repo.GetCommit(commitID)
+}
+
+// GetTagCommit returns the commit of given tag.
+func (repo *Repository) GetTagCommit(name string) (*Commit, error) {
+	commitID, err := repo.GetTagCommitID(name)
+	if err != nil {
+		return nil, err
+	}
+	return repo.GetCommit(commitID)
+}
+
+// GetRemoteBranchCommit returns the last commit of given remote branch.
+func (repo *Repository) GetRemoteBranchCommit(name string) (*Commit, error) {
+	commitID, err := repo.GetRemoteBranchCommitID(name)
+	if err != nil {
+		return nil, err
+	}
+	return repo.GetCommit(commitID)
+}
+
+func (repo *Repository) getCommitByPathWithID(id sha1, relpath string) (*Commit, error) {
+	// File name starts with ':' must be escaped.
+	if relpath[0] == ':' {
+		relpath = `\` + relpath
+	}
+
+	stdout, err := NewCommand("log", "-1", _PRETTY_LOG_FORMAT, id.String(), "--", relpath).RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	id, err = NewIDFromString(stdout)
+	if err != nil {
+		return nil, err
+	}
+
+	return repo.getCommit(id)
+}
+
+// GetCommitByPath returns the last commit of relative path.
+func (repo *Repository) GetCommitByPath(relpath string) (*Commit, error) {
+	stdout, err := NewCommand("log", "-1", _PRETTY_LOG_FORMAT, "--", relpath).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	commits, err := repo.parsePrettyFormatLogToList(stdout)
+	if err != nil {
+		return nil, err
+	}
+	return commits.Front().Value.(*Commit), nil
+}
+
+func (repo *Repository) CommitsByRangeSize(revision string, page, size int) (*list.List, error) {
+	stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*size),
+		"--max-count="+strconv.Itoa(size), _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	return repo.parsePrettyFormatLogToList(stdout)
+}
+
+var DefaultCommitsPageSize = 30
+
+func (repo *Repository) CommitsByRange(revision string, page int) (*list.List, error) {
+	return repo.CommitsByRangeSize(revision, page, DefaultCommitsPageSize)
+}
+
+func (repo *Repository) searchCommits(id sha1, keyword string) (*list.List, error) {
+	stdout, err := NewCommand("log", id.String(), "-100", "-i", "--grep="+keyword, _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	return repo.parsePrettyFormatLogToList(stdout)
+}
+
+func (repo *Repository) getFilesChanged(id1 string, id2 string) ([]string, error) {
+	stdout, err := NewCommand("diff", "--name-only", id1, id2).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	return strings.Split(string(stdout), "\n"), nil
+}
+
+func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
+	return commitsCount(repo.Path, revision, file)
+}
+
+func (repo *Repository) CommitsByFileAndRangeSize(revision, file string, page, size int) (*list.List, error) {
+	stdout, err := NewCommand("log", revision, "--skip="+strconv.Itoa((page-1)*size),
+		"--max-count="+strconv.Itoa(size), _PRETTY_LOG_FORMAT, "--", file).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	return repo.parsePrettyFormatLogToList(stdout)
+}
+
+func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) (*list.List, error) {
+	return repo.CommitsByFileAndRangeSize(revision, file, page, DefaultCommitsPageSize)
+}
+
+func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
+	stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
+	if err != nil {
+		return 0, err
+	}
+	return len(strings.Split(stdout, "\n")) - 1, nil
+}
+
+// CommitsBetween returns a list that contains commits between [last, before).
+func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) {
+	if version.Compare(gitVersion, "1.8.0", ">=") {
+		stdout, err := NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
+		if err != nil {
+			return nil, err
+		}
+		return repo.parsePrettyFormatLogToList(bytes.TrimSpace(stdout))
+	}
+
+	// Fallback to stupid solution, which iterates all commits of the repository
+	// if before is not an ancestor of last.
+	l := list.New()
+	if last == nil || last.ParentCount() == 0 {
+		return l, nil
+	}
+
+	var err error
+	cur := last
+	for {
+		if cur.ID.Equal(before.ID) {
+			break
+		}
+		l.PushBack(cur)
+		if cur.ParentCount() == 0 {
+			break
+		}
+		cur, err = cur.Parent(0)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return l, nil
+}
+
+func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, error) {
+	lastCommit, err := repo.GetCommit(last)
+	if err != nil {
+		return nil, err
+	}
+	beforeCommit, err := repo.GetCommit(before)
+	if err != nil {
+		return nil, err
+	}
+	return repo.CommitsBetween(lastCommit, beforeCommit)
+}
+
+func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
+	return commitsCount(repo.Path, start+"..."+end, "")
+}
+
+// The limit is depth, not total number of returned commits.
+func (repo *Repository) commitsBefore(l *list.List, parent *list.Element, id sha1, current, limit int) error {
+	// Reach the limit
+	if limit > 0 && current > limit {
+		return nil
+	}
+
+	commit, err := repo.getCommit(id)
+	if err != nil {
+		return fmt.Errorf("getCommit: %v", err)
+	}
+
+	var e *list.Element
+	if parent == nil {
+		e = l.PushBack(commit)
+	} else {
+		var in = parent
+		for {
+			if in == nil {
+				break
+			} else if in.Value.(*Commit).ID.Equal(commit.ID) {
+				return nil
+			} else if in.Next() == nil {
+				break
+			}
+
+			if in.Value.(*Commit).Committer.When.Equal(commit.Committer.When) {
+				break
+			}
+
+			if in.Value.(*Commit).Committer.When.After(commit.Committer.When) &&
+				in.Next().Value.(*Commit).Committer.When.Before(commit.Committer.When) {
+				break
+			}
+
+			in = in.Next()
+		}
+
+		e = l.InsertAfter(commit, in)
+	}
+
+	pr := parent
+	if commit.ParentCount() > 1 {
+		pr = e
+	}
+
+	for i := 0; i < commit.ParentCount(); i++ {
+		id, err := commit.ParentID(i)
+		if err != nil {
+			return err
+		}
+		err = repo.commitsBefore(l, pr, id, current+1, limit)
+		if err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) {
+	l := list.New()
+	return l, repo.commitsBefore(l, nil, id, 1, 0)
+}
+
+func (repo *Repository) getCommitsBeforeLimit(id sha1, num int) (*list.List, error) {
+	l := list.New()
+	return l, repo.commitsBefore(l, nil, id, 1, num)
+}

+ 400 - 0
vendor/github.com/G-Node/git-module/repo_diff.go

@@ -0,0 +1,400 @@
+// Copyright 2017 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// DiffLineType represents the type of a line in diff.
+type DiffLineType uint8
+
+const (
+	DIFF_LINE_PLAIN DiffLineType = iota + 1
+	DIFF_LINE_ADD
+	DIFF_LINE_DEL
+	DIFF_LINE_SECTION
+)
+
+// DiffFileType represents the file status in diff.
+type DiffFileType uint8
+
+const (
+	DIFF_FILE_ADD DiffFileType = iota + 1
+	DIFF_FILE_CHANGE
+	DIFF_FILE_DEL
+	DIFF_FILE_RENAME
+)
+
+// DiffLine represents a line in diff.
+type DiffLine struct {
+	LeftIdx  int
+	RightIdx int
+	Type     DiffLineType
+	Content  string
+}
+
+func (d *DiffLine) GetType() int {
+	return int(d.Type)
+}
+
+// DiffSection represents a section in diff.
+type DiffSection struct {
+	Name  string
+	Lines []*DiffLine
+}
+
+// Line returns a specific line by type (add or del) and file line number from a section.
+func (diffSection *DiffSection) Line(lineType DiffLineType, idx int) *DiffLine {
+	var (
+		difference    = 0
+		addCount      = 0
+		delCount      = 0
+		matchDiffLine *DiffLine
+	)
+
+LOOP:
+	for _, diffLine := range diffSection.Lines {
+		switch diffLine.Type {
+		case DIFF_LINE_ADD:
+			addCount++
+		case DIFF_LINE_DEL:
+			delCount++
+		default:
+			if matchDiffLine != nil {
+				break LOOP
+			}
+			difference = diffLine.RightIdx - diffLine.LeftIdx
+			addCount = 0
+			delCount = 0
+		}
+
+		switch lineType {
+		case DIFF_LINE_DEL:
+			if diffLine.RightIdx == 0 && diffLine.LeftIdx == idx-difference {
+				matchDiffLine = diffLine
+			}
+		case DIFF_LINE_ADD:
+			if diffLine.LeftIdx == 0 && diffLine.RightIdx == idx+difference {
+				matchDiffLine = diffLine
+			}
+		}
+	}
+
+	if addCount == delCount {
+		return matchDiffLine
+	}
+	return nil
+}
+
+// DiffFile represents a file in diff.
+type DiffFile struct {
+	Name               string
+	OldName            string
+	Index              string // 40-byte SHA, Changed/New: new SHA; Deleted: old SHA
+	Addition, Deletion int
+	Type               DiffFileType
+	IsCreated          bool
+	IsDeleted          bool
+	IsBin              bool
+	IsRenamed          bool
+	IsSubmodule        bool
+	Sections           []*DiffSection
+	IsIncomplete       bool
+}
+
+func (diffFile *DiffFile) GetType() int {
+	return int(diffFile.Type)
+}
+
+func (diffFile *DiffFile) NumSections() int {
+	return len(diffFile.Sections)
+}
+
+// Diff contains all information of a specific diff output.
+type Diff struct {
+	TotalAddition, TotalDeletion int
+	Files                        []*DiffFile
+	IsIncomplete                 bool
+}
+
+func (diff *Diff) NumFiles() int {
+	return len(diff.Files)
+}
+
+const _DIFF_HEAD = "diff --git "
+
+// ParsePatch takes a reader and parses everything it receives in diff format.
+func ParsePatch(done chan<- error, maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) *Diff {
+	var (
+		diff = &Diff{Files: make([]*DiffFile, 0)}
+
+		curFile    *DiffFile
+		curSection = &DiffSection{
+			Lines: make([]*DiffLine, 0, 10),
+		}
+
+		leftLine, rightLine int
+		lineCount           int
+		curFileLinesCount   int
+	)
+	input := bufio.NewReader(reader)
+	isEOF := false
+	for !isEOF {
+		// TODO: would input.ReadBytes be more memory-efficient?
+		line, err := input.ReadString('\n')
+		if err != nil {
+			if err == io.EOF {
+				isEOF = true
+			} else {
+				done <- fmt.Errorf("ReadString: %v", err)
+				return nil
+			}
+		}
+
+		if len(line) > 0 && line[len(line)-1] == '\n' {
+			// Remove line break.
+			line = line[:len(line)-1]
+		}
+
+		if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 {
+			continue
+		}
+
+		curFileLinesCount++
+		lineCount++
+
+		// Diff data too large, we only show the first about maxlines lines
+		if curFileLinesCount >= maxLines || len(line) >= maxLineCharacteres {
+			curFile.IsIncomplete = true
+		}
+
+		switch {
+		case line[0] == ' ':
+			diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
+			leftLine++
+			rightLine++
+			curSection.Lines = append(curSection.Lines, diffLine)
+			continue
+		case line[0] == '@':
+			curSection = &DiffSection{}
+			curFile.Sections = append(curFile.Sections, curSection)
+			ss := strings.Split(line, "@@")
+			diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line}
+			curSection.Lines = append(curSection.Lines, diffLine)
+
+			// Parse line number.
+			ranges := strings.Split(ss[1][1:], " ")
+			leftLine, _ = strconv.Atoi(strings.Split(ranges[0], ",")[0][1:])
+			if len(ranges) > 1 {
+				rightLine, _ = strconv.Atoi(strings.Split(ranges[1], ",")[0])
+			} else {
+				rightLine = leftLine
+			}
+			continue
+		case line[0] == '+':
+			curFile.Addition++
+			diff.TotalAddition++
+			diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine}
+			rightLine++
+			curSection.Lines = append(curSection.Lines, diffLine)
+			continue
+		case line[0] == '-':
+			curFile.Deletion++
+			diff.TotalDeletion++
+			diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine}
+			if leftLine > 0 {
+				leftLine++
+			}
+			curSection.Lines = append(curSection.Lines, diffLine)
+		case strings.HasPrefix(line, "Binary"):
+			curFile.IsBin = true
+			continue
+		}
+
+		// Get new file.
+		if strings.HasPrefix(line, _DIFF_HEAD) {
+			middle := -1
+
+			// Note: In case file name is surrounded by double quotes (it happens only in git-shell).
+			// e.g. diff --git "a/xxx" "b/xxx"
+			hasQuote := line[len(_DIFF_HEAD)] == '"'
+			if hasQuote {
+				middle = strings.Index(line, ` "b/`)
+			} else {
+				middle = strings.Index(line, " b/")
+			}
+
+			beg := len(_DIFF_HEAD)
+			a := line[beg+2 : middle]
+			b := line[middle+3:]
+			if hasQuote {
+				a = string(UnescapeChars([]byte(a[1 : len(a)-1])))
+				b = string(UnescapeChars([]byte(b[1 : len(b)-1])))
+			}
+
+			curFile = &DiffFile{
+				Name:     a,
+				Type:     DIFF_FILE_CHANGE,
+				Sections: make([]*DiffSection, 0, 10),
+			}
+			diff.Files = append(diff.Files, curFile)
+			if len(diff.Files) >= maxFiles {
+				diff.IsIncomplete = true
+				io.Copy(ioutil.Discard, reader)
+				break
+			}
+			curFileLinesCount = 0
+
+			// Check file diff type and submodule.
+		CHECK_TYPE:
+			for {
+				line, err := input.ReadString('\n')
+				if err != nil {
+					if err == io.EOF {
+						isEOF = true
+					} else {
+						done <- fmt.Errorf("ReadString: %v", err)
+						return nil
+					}
+				}
+
+				switch {
+				case strings.HasPrefix(line, "new file"):
+					curFile.Type = DIFF_FILE_ADD
+					curFile.IsCreated = true
+					curFile.IsSubmodule = strings.HasSuffix(line, " 160000\n")
+				case strings.HasPrefix(line, "deleted"):
+					curFile.Type = DIFF_FILE_DEL
+					curFile.IsDeleted = true
+					curFile.IsSubmodule = strings.HasSuffix(line, " 160000\n")
+				case strings.HasPrefix(line, "index"):
+					if curFile.IsDeleted {
+						curFile.Index = line[6:46]
+					} else if len(line) >= 88 {
+						curFile.Index = line[49:88]
+					} else {
+						curFile.Index = curFile.Name
+					}
+					break CHECK_TYPE
+				case strings.HasPrefix(line, "similarity index 100%"):
+					curFile.Type = DIFF_FILE_RENAME
+					curFile.IsRenamed = true
+					curFile.OldName = curFile.Name
+					curFile.Name = b
+					curFile.Index = b
+					break CHECK_TYPE
+				case strings.HasPrefix(line, "old mode"):
+					break CHECK_TYPE
+				}
+			}
+		}
+	}
+
+	done <- nil
+	return diff
+}
+
+// GetDiffRange returns a parsed diff object between given commits.
+func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
+	repo, err := OpenRepository(repoPath)
+	if err != nil {
+		return nil, err
+	}
+
+	commit, err := repo.GetCommit(afterCommitID)
+	if err != nil {
+		return nil, err
+	}
+
+	cmd := NewCommand()
+	if len(beforeCommitID) == 0 {
+		// First commit of repository
+		if commit.ParentCount() == 0 {
+			cmd.AddArguments("show", "--full-index", afterCommitID)
+		} else {
+			c, _ := commit.Parent(0)
+			cmd.AddArguments("diff", "--full-index", "-M", c.ID.String(), afterCommitID)
+		}
+	} else {
+		cmd.AddArguments("diff", "--full-index", "-M", beforeCommitID, afterCommitID)
+	}
+
+	stdout, w := io.Pipe()
+	done := make(chan error)
+	var diff *Diff
+	go func() {
+		diff = ParsePatch(done, maxLines, maxLineCharacteres, maxFiles, stdout)
+	}()
+
+	stderr := new(bytes.Buffer)
+	err = cmd.RunInDirTimeoutPipeline(2*time.Minute, repoPath, w, stderr)
+	w.Close() // Close writer to exit parsing goroutine
+	if err != nil {
+		return nil, concatenateError(err, stderr.String())
+	}
+
+	return diff, <-done
+}
+
+// RawDiffType represents the type of raw diff format.
+type RawDiffType string
+
+const (
+	RAW_DIFF_NORMAL RawDiffType = "diff"
+	RAW_DIFF_PATCH  RawDiffType = "patch"
+)
+
+// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
+func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
+	repo, err := OpenRepository(repoPath)
+	if err != nil {
+		return fmt.Errorf("OpenRepository: %v", err)
+	}
+
+	commit, err := repo.GetCommit(commitID)
+	if err != nil {
+		return err
+	}
+
+	cmd := NewCommand()
+	switch diffType {
+	case RAW_DIFF_NORMAL:
+		if commit.ParentCount() == 0 {
+			cmd.AddArguments("show", commitID)
+		} else {
+			c, _ := commit.Parent(0)
+			cmd.AddArguments("diff", "-M", c.ID.String(), commitID)
+		}
+	case RAW_DIFF_PATCH:
+		if commit.ParentCount() == 0 {
+			cmd.AddArguments("format-patch", "--no-signature", "--stdout", "--root", commitID)
+		} else {
+			c, _ := commit.Parent(0)
+			query := fmt.Sprintf("%s...%s", commitID, c.ID.String())
+			cmd.AddArguments("format-patch", "--no-signature", "--stdout", query)
+		}
+	default:
+		return fmt.Errorf("invalid diffType: %s", diffType)
+	}
+
+	stderr := new(bytes.Buffer)
+	if err = cmd.RunInDirPipeline(repoPath, writer, stderr); err != nil {
+		return concatenateError(err, stderr.String())
+	}
+	return nil
+}
+
+// GetDiffCommit returns a parsed diff object of given commit.
+func GetDiffCommit(repoPath, commitID string, maxLines, maxLineCharacteres, maxFiles int) (*Diff, error) {
+	return GetDiffRange(repoPath, "", commitID, maxLines, maxLineCharacteres, maxFiles)
+}

+ 13 - 0
vendor/github.com/G-Node/git-module/repo_hook.go

@@ -0,0 +1,13 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+func (repo *Repository) GetHook(name string) (*Hook, error) {
+	return GetHook(repo.Path, name)
+}
+
+func (repo *Repository) Hooks() ([]*Hook, error) {
+	return ListHooks(repo.Path)
+}

+ 14 - 0
vendor/github.com/G-Node/git-module/repo_object.go

@@ -0,0 +1,14 @@
+// Copyright 2014 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+type ObjectType string
+
+const (
+	OBJECT_COMMIT ObjectType = "commit"
+	OBJECT_TREE   ObjectType = "tree"
+	OBJECT_BLOB   ObjectType = "blob"
+	OBJECT_TAG    ObjectType = "tag"
+)

+ 81 - 0
vendor/github.com/G-Node/git-module/repo_pull.go

@@ -0,0 +1,81 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"container/list"
+	"fmt"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// PullRequestInfo represents needed information for a pull request.
+type PullRequestInfo struct {
+	MergeBase string
+	Commits   *list.List
+	NumFiles  int
+}
+
+// GetMergeBase checks and returns merge base of two branches.
+func (repo *Repository) GetMergeBase(base, head string) (string, error) {
+	stdout, err := NewCommand("merge-base", base, head).RunInDir(repo.Path)
+	if err != nil {
+		if strings.Contains(err.Error(), "exit status 1") {
+			return "", ErrNoMergeBase{}
+		}
+		return "", err
+	}
+	return strings.TrimSpace(stdout), nil
+}
+
+// GetPullRequestInfo generates and returns pull request information
+// between base and head branches of repositories.
+func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch string) (_ *PullRequestInfo, err error) {
+	var remoteBranch string
+
+	// We don't need a temporary remote for same repository.
+	if repo.Path != basePath {
+		// Add a temporary remote
+		tmpRemote := strconv.FormatInt(time.Now().UnixNano(), 10)
+		if err = repo.AddRemote(tmpRemote, basePath, true); err != nil {
+			return nil, fmt.Errorf("AddRemote: %v", err)
+		}
+		defer repo.RemoveRemote(tmpRemote)
+
+		remoteBranch = "remotes/" + tmpRemote + "/" + baseBranch
+	} else {
+		remoteBranch = baseBranch
+	}
+
+	prInfo := new(PullRequestInfo)
+	prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch)
+	if err != nil {
+		return nil, err
+	}
+
+	logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, _PRETTY_LOG_FORMAT).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
+	if err != nil {
+		return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
+	}
+
+	// Count number of changed files.
+	stdout, err := NewCommand("diff", "--name-only", remoteBranch+"..."+headBranch).RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	prInfo.NumFiles = len(strings.Split(stdout, "\n")) - 1
+
+	return prInfo, nil
+}
+
+// GetPatch generates and returns patch data between given revisions.
+func (repo *Repository) GetPatch(base, head string) ([]byte, error) {
+	return NewCommand("diff", "-p", "--binary", base, head).RunInDirBytes(repo.Path)
+}

+ 209 - 0
vendor/github.com/G-Node/git-module/repo_tag.go

@@ -0,0 +1,209 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/mcuadros/go-version"
+)
+
+const TAG_PREFIX = "refs/tags/"
+
+// IsTagExist returns true if given tag exists in the repository.
+func IsTagExist(repoPath, name string) bool {
+	return IsReferenceExist(repoPath, TAG_PREFIX+name)
+}
+
+func (repo *Repository) IsTagExist(name string) bool {
+	return IsTagExist(repo.Path, name)
+}
+
+func (repo *Repository) CreateTag(name, revision string) error {
+	_, err := NewCommand("tag", name, revision).RunInDir(repo.Path)
+	return err
+}
+
+func (repo *Repository) getTag(id sha1) (*Tag, error) {
+	t, ok := repo.tagCache.Get(id.String())
+	if ok {
+		log("Hit cache: %s", id)
+		return t.(*Tag), nil
+	}
+
+	// Get tag type
+	tp, err := NewCommand("cat-file", "-t", id.String()).RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	tp = strings.TrimSpace(tp)
+
+	// Tag is a commit.
+	if ObjectType(tp) == OBJECT_COMMIT {
+		tag := &Tag{
+			ID:     id,
+			Object: id,
+			Type:   string(OBJECT_COMMIT),
+			repo:   repo,
+		}
+
+		repo.tagCache.Set(id.String(), tag)
+		return tag, nil
+	}
+
+	// Tag with message.
+	data, err := NewCommand("cat-file", "-p", id.String()).RunInDirBytes(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	tag, err := parseTagData(data)
+	if err != nil {
+		return nil, err
+	}
+
+	tag.ID = id
+	tag.repo = repo
+
+	repo.tagCache.Set(id.String(), tag)
+	return tag, nil
+}
+
+// GetTag returns a Git tag by given name.
+func (repo *Repository) GetTag(name string) (*Tag, error) {
+	stdout, err := NewCommand("show-ref", "--tags", name).RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	id, err := NewIDFromString(strings.Split(stdout, " ")[0])
+	if err != nil {
+		return nil, err
+	}
+
+	tag, err := repo.getTag(id)
+	if err != nil {
+		return nil, err
+	}
+	tag.Name = name
+	return tag, nil
+}
+
+// GetTags returns all tags of the repository.
+func (repo *Repository) GetTags() ([]string, error) {
+	cmd := NewCommand("tag", "-l")
+	if version.Compare(gitVersion, "2.0.0", ">=") {
+		cmd.AddArguments("--sort=-v:refname")
+	}
+
+	stdout, err := cmd.RunInDir(repo.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	tags := strings.Split(stdout, "\n")
+	tags = tags[:len(tags)-1]
+
+	if version.Compare(gitVersion, "2.0.0", "<") {
+		version.Sort(tags)
+
+		// Reverse order
+		for i := 0; i < len(tags)/2; i++ {
+			j := len(tags) - i - 1
+			tags[i], tags[j] = tags[j], tags[i]
+		}
+	}
+
+	return tags, nil
+}
+
+type TagsResult struct {
+	// Indicates whether results include the latest tag.
+	HasLatest bool
+	// If results do not include the latest tag, a indicator 'after' to go back.
+	PreviousAfter string
+	// Indicates whether results include the oldest tag.
+	ReachEnd bool
+	// List of returned tags.
+	Tags []string
+}
+
+// GetTagsAfter returns list of tags 'after' (exlusive) given tag.
+func (repo *Repository) GetTagsAfter(after string, limit int) (*TagsResult, error) {
+	allTags, err := repo.GetTags()
+	if err != nil {
+		return nil, fmt.Errorf("GetTags: %v", err)
+	}
+
+	if limit < 0 {
+		limit = 0
+	}
+
+	numAllTags := len(allTags)
+	if len(after) == 0 && limit == 0 {
+		return &TagsResult{
+			HasLatest: true,
+			ReachEnd:  true,
+			Tags:      allTags,
+		}, nil
+	} else if len(after) == 0 && limit > 0 {
+		endIdx := limit
+		if limit >= numAllTags {
+			endIdx = numAllTags
+		}
+		return &TagsResult{
+			HasLatest: true,
+			ReachEnd:  limit >= numAllTags,
+			Tags:      allTags[:endIdx],
+		}, nil
+	}
+
+	previousAfter := ""
+	hasMatch := false
+	tags := make([]string, 0, len(allTags))
+	for i := range allTags {
+		if hasMatch {
+			tags = allTags[i:]
+			break
+		}
+		if allTags[i] == after {
+			hasMatch = true
+			if limit > 0 && i-limit >= 0 {
+				previousAfter = allTags[i-limit]
+			}
+			continue
+		}
+	}
+
+	if !hasMatch {
+		tags = allTags
+	}
+
+	// If all tags after match is equal to the limit, it reaches the oldest tag as well.
+	if limit == 0 || len(tags) <= limit {
+		return &TagsResult{
+			HasLatest:     !hasMatch,
+			PreviousAfter: previousAfter,
+			ReachEnd:      true,
+			Tags:          tags,
+		}, nil
+	}
+	return &TagsResult{
+		HasLatest:     !hasMatch,
+		PreviousAfter: previousAfter,
+		Tags:          tags[:limit],
+	}, nil
+}
+
+// DeleteTag deletes a tag from the repository
+func (repo *Repository) DeleteTag(name string) error {
+	cmd := NewCommand("tag", "-d")
+
+	cmd.AddArguments(name)
+	_, err := cmd.RunInDir(repo.Path)
+
+	return err
+}

+ 26 - 0
vendor/github.com/G-Node/git-module/repo_tree.go

@@ -0,0 +1,26 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+func (repo *Repository) getTree(id sha1) (*Tree, error) {
+	treePath := filepathFromSHA1(repo.Path, id.String())
+	if isFile(treePath) {
+		_, err := NewCommand("ls-tree", id.String()).RunInDir(repo.Path)
+		if err != nil {
+			return nil, ErrNotExist{id.String(), ""}
+		}
+	}
+
+	return NewTree(repo, id), nil
+}
+
+// Find the tree object in the repository.
+func (repo *Repository) GetTree(idStr string) (*Tree, error) {
+	id, err := NewIDFromString(idStr)
+	if err != nil {
+		return nil, err
+	}
+	return repo.getTree(id)
+}

+ 93 - 0
vendor/github.com/G-Node/git-module/sha1.go

@@ -0,0 +1,93 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"encoding/hex"
+	"fmt"
+	"strings"
+)
+
+const EMPTY_SHA = "0000000000000000000000000000000000000000"
+
+type sha1 [20]byte
+
+// Equal returns true if s has the same sha1 as caller.
+// Support 40-length-string, []byte, sha1.
+func (id sha1) Equal(s2 interface{}) bool {
+	switch v := s2.(type) {
+	case string:
+		if len(v) != 40 {
+			return false
+		}
+		return v == id.String()
+	case []byte:
+		if len(v) != 20 {
+			return false
+		}
+		for i, v := range v {
+			if id[i] != v {
+				return false
+			}
+		}
+	case sha1:
+		for i, v := range v {
+			if id[i] != v {
+				return false
+			}
+		}
+	default:
+		return false
+	}
+	return true
+}
+
+// String returns string (hex) representation of the Oid.
+func (s sha1) String() string {
+	result := make([]byte, 0, 40)
+	hexvalues := []byte("0123456789abcdef")
+	for i := 0; i < 20; i++ {
+		result = append(result, hexvalues[s[i]>>4])
+		result = append(result, hexvalues[s[i]&0xf])
+	}
+	return string(result)
+}
+
+// MustID always creates a new sha1 from a [20]byte array with no validation of input.
+func MustID(b []byte) sha1 {
+	var id sha1
+	for i := 0; i < 20; i++ {
+		id[i] = b[i]
+	}
+	return id
+}
+
+// NewID creates a new sha1 from a [20]byte array.
+func NewID(b []byte) (sha1, error) {
+	if len(b) != 20 {
+		return sha1{}, fmt.Errorf("Length must be 20: %v", b)
+	}
+	return MustID(b), nil
+}
+
+// MustIDFromString always creates a new sha from a ID with no validation of input.
+func MustIDFromString(s string) sha1 {
+	b, _ := hex.DecodeString(s)
+	return MustID(b)
+}
+
+// NewIDFromString creates a new sha1 from a ID string of length 40.
+func NewIDFromString(s string) (sha1, error) {
+	var id sha1
+	s = strings.TrimSpace(s)
+	if len(s) != 40 {
+		return id, fmt.Errorf("Length must be 40: %s", s)
+	}
+	b, err := hex.DecodeString(s)
+	if err != nil {
+		return id, err
+	}
+	return NewID(b)
+}

+ 48 - 0
vendor/github.com/G-Node/git-module/signature.go

@@ -0,0 +1,48 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"strconv"
+	"time"
+)
+
+// Signature represents the Author or Committer information.
+type Signature struct {
+	Email string
+	Name  string
+	When  time.Time
+}
+
+// Helper to get a signature from the commit line, which looks like these:
+//     author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
+//     author Patrick Gundlach <gundlach@speedata.de> Thu, 07 Apr 2005 22:13:13 +0200
+// but without the "author " at the beginning (this method should)
+// be used for author and committer.
+//
+// FIXME: include timezone for timestamp!
+func newSignatureFromCommitline(line []byte) (_ *Signature, err error) {
+	sig := new(Signature)
+	emailStart := bytes.IndexByte(line, '<')
+	sig.Name = string(line[:emailStart-1])
+	emailEnd := bytes.IndexByte(line, '>')
+	sig.Email = string(line[emailStart+1 : emailEnd])
+
+	// Check date format.
+	firstChar := line[emailEnd+2]
+	if firstChar >= 48 && firstChar <= 57 {
+		timestop := bytes.IndexByte(line[emailEnd+2:], ' ')
+		timestring := string(line[emailEnd+2 : emailEnd+2+timestop])
+		seconds, _ := strconv.ParseInt(timestring, 10, 64)
+		sig.When = time.Unix(seconds, 0)
+	} else {
+		sig.When, err = time.Parse("Mon Jan _2 15:04:05 2006 -0700", string(line[emailEnd+2:]))
+		if err != nil {
+			return nil, err
+		}
+	}
+	return sig, nil
+}

+ 78 - 0
vendor/github.com/G-Node/git-module/submodule.go

@@ -0,0 +1,78 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import "strings"
+
+type SubModule struct {
+	Name string
+	URL  string
+}
+
+// SubModuleFile represents a file with submodule type.
+type SubModuleFile struct {
+	*Commit
+
+	refURL string
+	refID  string
+}
+
+func NewSubModuleFile(c *Commit, refURL, refID string) *SubModuleFile {
+	return &SubModuleFile{
+		Commit: c,
+		refURL: refURL,
+		refID:  refID,
+	}
+}
+
+// RefURL guesses and returns reference URL.
+func (sf *SubModuleFile) RefURL(urlPrefix string, parentPath string) string {
+	if sf.refURL == "" {
+		return ""
+	}
+
+	url := strings.TrimSuffix(sf.refURL, ".git")
+
+	// git://xxx/user/repo
+	if strings.HasPrefix(url, "git://") {
+		return "http://" + strings.TrimPrefix(url, "git://")
+	}
+
+	// http[s]://xxx/user/repo
+	if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
+		return url
+	}
+
+	// Relative url prefix check (according to git submodule documentation)
+	if strings.HasPrefix(url, "./") || strings.HasPrefix(url, "../") {
+		// ...construct and return correct submodule url here...
+		idx := strings.Index(parentPath, "/src/")
+		if idx == -1 {
+			return url
+		}
+		return strings.TrimSuffix(urlPrefix, "/") + parentPath[:idx] + "/" + url
+	}
+
+	// sysuser@xxx:user/repo
+	i := strings.Index(url, "@")
+	j := strings.LastIndex(url, ":")
+
+	// Only process when i < j because git+ssh://git@git.forwardbias.in/npploader.git
+	if i > -1 && j > -1 && i < j {
+		// fix problem with reverse proxy works only with local server
+		if strings.Contains(urlPrefix, url[i+1:j]) {
+			return urlPrefix + url[j+1:]
+		} else {
+			return "http://" + url[i+1:j] + "/" + url[j+1:]
+		}
+	}
+
+	return url
+}
+
+// RefID returns reference ID.
+func (sf *SubModuleFile) RefID() string {
+	return sf.refID
+}

+ 65 - 0
vendor/github.com/G-Node/git-module/tag.go

@@ -0,0 +1,65 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import "bytes"
+
+// Tag represents a Git tag.
+type Tag struct {
+	Name    string
+	ID      sha1
+	repo    *Repository
+	Object  sha1 // The id of this commit object
+	Type    string
+	Tagger  *Signature
+	Message string
+}
+
+func (tag *Tag) Commit() (*Commit, error) {
+	return tag.repo.getCommit(tag.Object)
+}
+
+// Parse commit information from the (uncompressed) raw
+// data from the commit object.
+// \n\n separate headers from message
+func parseTagData(data []byte) (*Tag, error) {
+	tag := new(Tag)
+	// we now have the contents of the commit object. Let's investigate...
+	nextline := 0
+l:
+	for {
+		eol := bytes.IndexByte(data[nextline:], '\n')
+		switch {
+		case eol > 0:
+			line := data[nextline : nextline+eol]
+			spacepos := bytes.IndexByte(line, ' ')
+			reftype := line[:spacepos]
+			switch string(reftype) {
+			case "object":
+				id, err := NewIDFromString(string(line[spacepos+1:]))
+				if err != nil {
+					return nil, err
+				}
+				tag.Object = id
+			case "type":
+				// A commit can have one or more parents
+				tag.Type = string(line[spacepos+1:])
+			case "tagger":
+				sig, err := newSignatureFromCommitline(line[spacepos+1:])
+				if err != nil {
+					return nil, err
+				}
+				tag.Tagger = sig
+			}
+			nextline += eol + 1
+		case eol == 0:
+			tag.Message = string(data[nextline+1:])
+			break l
+		default:
+			break l
+		}
+	}
+	return tag, nil
+}

+ 149 - 0
vendor/github.com/G-Node/git-module/tree.go

@@ -0,0 +1,149 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+)
+
+// Tree represents a flat directory listing.
+type Tree struct {
+	ID   sha1
+	repo *Repository
+
+	// parent tree
+	ptree *Tree
+
+	entries       Entries
+	entriesParsed bool
+}
+
+func NewTree(repo *Repository, id sha1) *Tree {
+	return &Tree{
+		ID:   id,
+		repo: repo,
+	}
+}
+
+// Predefine []byte variables to avoid runtime allocations.
+var (
+	escapedSlash = []byte(`\\`)
+	regularSlash = []byte(`\`)
+	escapedTab   = []byte(`\t`)
+	regularTab   = []byte("\t")
+)
+
+// UnescapeChars reverses escaped characters.
+func UnescapeChars(in []byte) []byte {
+	// LEGACY [Go 1.7]: use more expressive bytes.ContainsAny
+	if bytes.IndexAny(in, "\\\t") == -1 {
+		return in
+	}
+
+	out := bytes.Replace(in, escapedSlash, regularSlash, -1)
+	out = bytes.Replace(out, escapedTab, regularTab, -1)
+	return out
+}
+
+// parseTreeData parses tree information from the (uncompressed) raw
+// data from the tree object.
+func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) {
+	entries := make([]*TreeEntry, 0, 10)
+	l := len(data)
+	pos := 0
+	for pos < l {
+		entry := new(TreeEntry)
+		entry.ptree = tree
+		step := 6
+		switch string(data[pos : pos+step]) {
+		case "100644", "100664":
+			entry.mode = ENTRY_MODE_BLOB
+			entry.Type = OBJECT_BLOB
+		case "100755":
+			entry.mode = ENTRY_MODE_EXEC
+			entry.Type = OBJECT_BLOB
+		case "120000":
+			entry.mode = ENTRY_MODE_SYMLINK
+			entry.Type = OBJECT_BLOB
+		case "160000":
+			entry.mode = ENTRY_MODE_COMMIT
+			entry.Type = OBJECT_COMMIT
+
+			step = 8
+		case "040000":
+			entry.mode = ENTRY_MODE_TREE
+			entry.Type = OBJECT_TREE
+		default:
+			return nil, fmt.Errorf("unknown type: %v", string(data[pos:pos+step]))
+		}
+		pos += step + 6 // Skip string type of entry type.
+
+		step = 40
+		id, err := NewIDFromString(string(data[pos : pos+step]))
+		if err != nil {
+			return nil, err
+		}
+		entry.ID = id
+		pos += step + 1 // Skip half of sha1.
+
+		step = bytes.IndexByte(data[pos:], '\n')
+
+		// In case entry name is surrounded by double quotes(it happens only in git-shell).
+		if data[pos] == '"' {
+			entry.name = string(UnescapeChars(data[pos+1 : pos+step-1]))
+		} else {
+			entry.name = string(data[pos : pos+step])
+		}
+
+		pos += step + 1
+		entries = append(entries, entry)
+	}
+	return entries, nil
+}
+
+func (t *Tree) SubTree(rpath string) (*Tree, error) {
+	if len(rpath) == 0 {
+		return t, nil
+	}
+
+	paths := strings.Split(rpath, "/")
+	var (
+		err error
+		g   = t
+		p   = t
+		te  *TreeEntry
+	)
+	for _, name := range paths {
+		te, err = p.GetTreeEntryByPath(name)
+		if err != nil {
+			return nil, err
+		}
+
+		g, err = t.repo.getTree(te.ID)
+		if err != nil {
+			return nil, err
+		}
+		g.ptree = p
+		p = g
+	}
+	return g, nil
+}
+
+// ListEntries returns all entries of current tree.
+func (t *Tree) ListEntries() (Entries, error) {
+	if t.entriesParsed {
+		return t.entries, nil
+	}
+	t.entriesParsed = true
+
+	stdout, err := NewCommand("ls-tree", t.ID.String()).RunInDirBytes(t.repo.Path)
+	if err != nil {
+		return nil, err
+	}
+	t.entries, err = parseTreeData(t, stdout)
+	return t.entries, err
+}

+ 57 - 0
vendor/github.com/G-Node/git-module/tree_blob.go

@@ -0,0 +1,57 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"path"
+	"strings"
+)
+
+func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
+	if len(relpath) == 0 {
+		return &TreeEntry{
+			ID:   t.ID,
+			Type: OBJECT_TREE,
+			mode: ENTRY_MODE_TREE,
+		}, nil
+	}
+
+	relpath = path.Clean(relpath)
+	parts := strings.Split(relpath, "/")
+	var err error
+	tree := t
+	for i, name := range parts {
+		if i == len(parts)-1 {
+			entries, err := tree.ListEntries()
+			if err != nil {
+				return nil, err
+			}
+			for _, v := range entries {
+				if v.name == name {
+					return v, nil
+				}
+			}
+		} else {
+			tree, err = tree.SubTree(name)
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return nil, ErrNotExist{"", relpath}
+}
+
+func (t *Tree) GetBlobByPath(relpath string) (*Blob, error) {
+	entry, err := t.GetTreeEntryByPath(relpath)
+	if err != nil {
+		return nil, err
+	}
+
+	if !entry.IsDir() {
+		return entry.Blob(), nil
+	}
+
+	return nil, ErrNotExist{"", relpath}
+}

+ 226 - 0
vendor/github.com/G-Node/git-module/tree_entry.go

@@ -0,0 +1,226 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"path"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+type EntryMode int
+
+// There are only a few file modes in Git. They look like unix file modes, but they can only be
+// one of these.
+const (
+	ENTRY_MODE_BLOB    EntryMode = 0100644
+	ENTRY_MODE_EXEC    EntryMode = 0100755
+	ENTRY_MODE_SYMLINK EntryMode = 0120000
+	ENTRY_MODE_COMMIT  EntryMode = 0160000
+	ENTRY_MODE_TREE    EntryMode = 0040000
+)
+
+type TreeEntry struct {
+	ID   sha1
+	Type ObjectType
+
+	mode EntryMode
+	name string
+
+	ptree *Tree
+
+	commited bool
+
+	size  int64
+	sized bool
+}
+
+func (te *TreeEntry) Name() string {
+	return te.name
+}
+
+func (te *TreeEntry) Size() int64 {
+	if te.IsDir() {
+		return 0
+	} else if te.sized {
+		return te.size
+	}
+
+	stdout, err := NewCommand("cat-file", "-s", te.ID.String()).RunInDir(te.ptree.repo.Path)
+	if err != nil {
+		return 0
+	}
+
+	te.sized = true
+	te.size, _ = strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
+	return te.size
+}
+
+func (te *TreeEntry) IsSubModule() bool {
+	return te.mode == ENTRY_MODE_COMMIT
+}
+
+func (te *TreeEntry) IsDir() bool {
+	return te.mode == ENTRY_MODE_TREE
+}
+
+func (te *TreeEntry) IsLink() bool {
+	return te.mode == ENTRY_MODE_SYMLINK
+}
+
+func (te *TreeEntry) Blob() *Blob {
+	return &Blob{
+		repo:      te.ptree.repo,
+		TreeEntry: te,
+	}
+}
+
+type Entries []*TreeEntry
+
+var sorter = []func(t1, t2 *TreeEntry) bool{
+	func(t1, t2 *TreeEntry) bool {
+		return (t1.IsDir() || t1.IsSubModule()) && !t2.IsDir() && !t2.IsSubModule()
+	},
+	func(t1, t2 *TreeEntry) bool {
+		return t1.name < t2.name
+	},
+}
+
+func (tes Entries) Len() int      { return len(tes) }
+func (tes Entries) Swap(i, j int) { tes[i], tes[j] = tes[j], tes[i] }
+func (tes Entries) Less(i, j int) bool {
+	t1, t2 := tes[i], tes[j]
+	var k int
+	for k = 0; k < len(sorter)-1; k++ {
+		sort := sorter[k]
+		switch {
+		case sort(t1, t2):
+			return true
+		case sort(t2, t1):
+			return false
+		}
+	}
+	return sorter[k](t1, t2)
+}
+
+func (tes Entries) Sort() {
+	sort.Sort(tes)
+}
+
+var defaultConcurrency = runtime.NumCPU()
+
+type commitInfo struct {
+	entryName string
+	infos     []interface{}
+	err       error
+}
+
+// GetCommitsInfo takes advantages of concurrency to speed up getting information
+// of all commits that are corresponding to these entries. This method will automatically
+// choose the right number of goroutine (concurrency) to use related of the host CPU.
+func (tes Entries) GetCommitsInfo(commit *Commit, treePath string) ([][]interface{}, error) {
+	return tes.GetCommitsInfoWithCustomConcurrency(commit, treePath, 0)
+}
+
+// GetCommitsInfoWithCustomConcurrency takes advantages of concurrency to speed up getting information
+// of all commits that are corresponding to these entries. If the given maxConcurrency is negative or
+// equal to zero:  the right number of goroutine (concurrency) to use will be choosen related of the
+// host CPU.
+func (tes Entries) GetCommitsInfoWithCustomConcurrency(commit *Commit, treePath string, maxConcurrency int) ([][]interface{}, error) {
+	if len(tes) == 0 {
+		return nil, nil
+	}
+
+	if maxConcurrency <= 0 {
+		maxConcurrency = defaultConcurrency
+	}
+
+	// Length of taskChan determines how many goroutines (subprocesses) can run at the same time.
+	// The length of revChan should be same as taskChan so goroutines whoever finished job can
+	// exit as early as possible, only store data inside channel.
+	taskChan := make(chan bool, maxConcurrency)
+	revChan := make(chan commitInfo, maxConcurrency)
+	doneChan := make(chan error)
+
+	// Receive loop will exit when it collects same number of data pieces as tree entries.
+	// It notifies doneChan before exits or notify early with possible error.
+	infoMap := make(map[string][]interface{}, len(tes))
+	go func() {
+		i := 0
+		for info := range revChan {
+			if info.err != nil {
+				doneChan <- info.err
+				return
+			}
+
+			infoMap[info.entryName] = info.infos
+			i++
+			if i == len(tes) {
+				break
+			}
+		}
+		doneChan <- nil
+	}()
+
+	for i := range tes {
+		// When taskChan is idle (or has empty slots), put operation will not block.
+		// However when taskChan is full, code will block and wait any running goroutines to finish.
+		taskChan <- true
+
+		if tes[i].Type != OBJECT_COMMIT {
+			go func(i int) {
+				cinfo := commitInfo{entryName: tes[i].Name()}
+				c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name()))
+				if err != nil {
+					cinfo.err = fmt.Errorf("GetCommitByPath (%s/%s): %v", treePath, tes[i].Name(), err)
+				} else {
+					cinfo.infos = []interface{}{tes[i], c}
+				}
+				revChan <- cinfo
+				<-taskChan // Clear one slot from taskChan to allow new goroutines to start.
+			}(i)
+			continue
+		}
+
+		// Handle submodule
+		go func(i int) {
+			cinfo := commitInfo{entryName: tes[i].Name()}
+			sm, err := commit.GetSubModule(path.Join(treePath, tes[i].Name()))
+			if err != nil && !IsErrNotExist(err) {
+				cinfo.err = fmt.Errorf("GetSubModule (%s/%s): %v", treePath, tes[i].Name(), err)
+				revChan <- cinfo
+				return
+			}
+
+			smURL := ""
+			if sm != nil {
+				smURL = sm.URL
+			}
+
+			c, err := commit.GetCommitByPath(filepath.Join(treePath, tes[i].Name()))
+			if err != nil {
+				cinfo.err = fmt.Errorf("GetCommitByPath (%s/%s): %v", treePath, tes[i].Name(), err)
+			} else {
+				cinfo.infos = []interface{}{tes[i], NewSubModuleFile(c, smURL, tes[i].ID.String())}
+			}
+			revChan <- cinfo
+			<-taskChan
+		}(i)
+	}
+
+	if err := <-doneChan; err != nil {
+		return nil, err
+	}
+
+	commitsInfo := make([][]interface{}, len(tes))
+	for i := 0; i < len(tes); i++ {
+		commitsInfo[i] = infoMap[tes[i].Name()]
+	}
+	return commitsInfo, nil
+}

+ 93 - 0
vendor/github.com/G-Node/git-module/utils.go

@@ -0,0 +1,93 @@
+// Copyright 2015 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package git
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+	"sync"
+)
+
+// objectCache provides thread-safe cache opeations.
+type objectCache struct {
+	lock  sync.RWMutex
+	cache map[string]interface{}
+}
+
+func newObjectCache() *objectCache {
+	return &objectCache{
+		cache: make(map[string]interface{}, 10),
+	}
+}
+
+func (oc *objectCache) Set(id string, obj interface{}) {
+	oc.lock.Lock()
+	defer oc.lock.Unlock()
+
+	oc.cache[id] = obj
+}
+
+func (oc *objectCache) Get(id string) (interface{}, bool) {
+	oc.lock.RLock()
+	defer oc.lock.RUnlock()
+
+	obj, has := oc.cache[id]
+	return obj, has
+}
+
+// isDir returns true if given path is a directory,
+// or returns false when it's a file or does not exist.
+func isDir(dir string) bool {
+	f, e := os.Stat(dir)
+	if e != nil {
+		return false
+	}
+	return f.IsDir()
+}
+
+// isFile returns true if given path is a file,
+// or returns false when it's a directory or does not exist.
+func isFile(filePath string) bool {
+	f, e := os.Stat(filePath)
+	if e != nil {
+		return false
+	}
+	return !f.IsDir()
+}
+
+// isExist checks whether a file or directory exists.
+// It returns false when the file or directory does not exist.
+func isExist(path string) bool {
+	_, err := os.Stat(path)
+	return err == nil || os.IsExist(err)
+}
+
+func concatenateError(err error, stderr string) error {
+	if len(stderr) == 0 {
+		return err
+	}
+	return fmt.Errorf("%v - %s", err, stderr)
+}
+
+// If the object is stored in its own file (i.e not in a pack file),
+// this function returns the full path to the object file.
+// It does not test if the file exists.
+func filepathFromSHA1(rootdir, sha1 string) string {
+	return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:])
+}
+
+func RefEndName(refStr string) string {
+	if strings.HasPrefix(refStr, BRANCH_PREFIX) {
+		return refStr[len(BRANCH_PREFIX):]
+	}
+
+	if strings.HasPrefix(refStr, TAG_PREFIX) {
+		return refStr[len(TAG_PREFIX):]
+	}
+
+	return refStr
+}

+ 29 - 0
vendor/github.com/G-Node/go-annex/LICENSE

@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2017, German Neuroinformatics Node
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* 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.
+
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+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.

+ 44 - 0
vendor/github.com/G-Node/go-annex/add.go

@@ -0,0 +1,44 @@
+package gannex
+
+import (
+	"github.com/G-Node/git-module"
+)
+
+const (
+	BYTE     = 1.0
+	KILOBYTE = 1024 * BYTE
+	MEGABYTE = 1024 * KILOBYTE
+	GIGABYTE = 1024 * MEGABYTE
+	TERABYTE = 1024 * GIGABYTE
+)
+
+type ACommand struct {
+	git.Command
+	name string
+	args []string
+	env  []string
+}
+
+func AInit(dir string, args ...string) (string, error) {
+	cmd := git.NewACommand("init")
+	return cmd.AddArguments(args...).RunInDir(dir)
+}
+
+func AUInit(dir string, args ...string) (string, error) {
+	cmd := git.NewACommand("uninit")
+	return cmd.AddArguments(args...).RunInDir(dir)
+}
+func Worm(dir string) (string, error) {
+	cmd := git.NewCommand("config", "annex.backends", "WORM")
+	return cmd.RunInDir(dir)
+}
+
+func ASync(dir string, args ...string) (string, error) {
+	cmd := git.NewACommand("sync")
+	return cmd.AddArguments(args...).RunInDir(dir)
+}
+
+func Add(filename, dir string) (string, error) {
+	cmd := git.NewACommand("add", filename)
+	return cmd.RunInDir(dir)
+}

+ 58 - 0
vendor/github.com/G-Node/go-annex/file.go

@@ -0,0 +1,58 @@
+package gannex
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"io"
+	"fmt"
+	"log"
+)
+
+type AFile struct {
+	Filepath  string
+	OFilename string
+	Info      os.FileInfo
+}
+
+type AnnexFileNotFound struct {
+	error
+}
+
+func NewAFile(annexpath, repopath, Ofilename string, APFileC []byte) (*AFile, error) {
+	nAF := &AFile{OFilename: Ofilename}
+	pathParts := strings.SplitAfter(string(APFileC), string(os.PathSeparator))
+	filename := strings.TrimSpace(pathParts[len(pathParts)-1])
+
+	// lets find the annex file
+	filepath.Walk(filepath.Join(annexpath, repopath), func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			log.Printf("%v", err)
+			return filepath.SkipDir
+		}
+		if info.IsDir() {
+			return nil
+		} else if info.Name() == filename {
+			nAF.Filepath = path
+			nAF.Info = info
+			return io.EOF
+		}
+		return nil
+	})
+	if nAF.Filepath != "" {
+		return nAF, nil
+	} else {
+		return nil, AnnexFileNotFound{error: fmt.Errorf("Could not find File: %s anywhere below: %s", filename,
+			filepath.Join(annexpath, repopath))}
+	}
+
+}
+
+func (af *AFile) Open() (*os.File, error) {
+	fp, err := os.Open(af.Filepath)
+	if err != nil {
+		return nil, err
+	}
+	return fp, nil
+
+}

+ 58 - 0
vendor/github.com/G-Node/go-annex/file.go.orig

@@ -0,0 +1,58 @@
+package gannex
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+	"io"
+	"fmt"
+	"log"
+)
+
+type AFile struct {
+	Filepath  string
+	OFilename string
+	Info      os.FileInfo
+}
+
+type AnnexFileNotFound struct {
+	error
+}
+
+func NewAFile(annexpath, repopath, Ofilename string, APFileC []byte) (*AFile, error) {
+	nAF := &AFile{OFilename: Ofilename}
+	pathParts := strings.SplitAfter(string(APFileC), string(os.PathSeparator))
+	filename := strings.TrimSpace(pathParts[len(pathParts)-1])
+
+	// lets find the annex file
+	filepath.Walk(filepath.Join(annexpath, repopath), func(path string, info os.FileInfo, err error) error {
+		if err != nil {
+			log.Printf("%v", err)
+			return filepath.SkipDir
+		}
+		if info.IsDir() {
+			return nil
+		} else if info.Name() == filename {
+			nAF.Filepath = path
+			nAF.Info = info
+			return io.EOF
+		}
+		return nil
+	})
+	if nAF.Filepath != "" {
+		return nAF, nil
+	} else {
+		return nil, AnnexFileNotFound{error: fmt.Errorf("Could not find File: %s anywhere below: %s", filename,
+			filepath.Join(annexpath, repopath))}
+	}
+
+}
+
+func (af *AFile) Open() (*os.File, error) {
+	fp, err := os.Open(af.Filepath)
+	if err != nil {
+		return nil, err
+	}
+	return fp, nil
+
+}

+ 5 - 0
vendor/github.com/G-Node/go-annex/util.go

@@ -0,0 +1,5 @@
+package gannex
+
+func isAnnexed(dir string) (bool, error) {
+	return false, nil
+}

+ 24 - 0
vendor/github.com/gopherjs/gopherjs/LICENSE

@@ -0,0 +1,24 @@
+Copyright (c) 2013 Richard Musiol. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+   * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+   * 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
+OWNER 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.

+ 168 - 0
vendor/github.com/gopherjs/gopherjs/js/js.go

@@ -0,0 +1,168 @@
+// Package js provides functions for interacting with native JavaScript APIs. Calls to these functions are treated specially by GopherJS and translated directly to their corresponding JavaScript syntax.
+//
+// Use MakeWrapper to expose methods to JavaScript. When passing values directly, the following type conversions are performed:
+//
+//  | Go type               | JavaScript type       | Conversions back to interface{} |
+//  | --------------------- | --------------------- | ------------------------------- |
+//  | bool                  | Boolean               | bool                            |
+//  | integers and floats   | Number                | float64                         |
+//  | string                | String                | string                          |
+//  | []int8                | Int8Array             | []int8                          |
+//  | []int16               | Int16Array            | []int16                         |
+//  | []int32, []int        | Int32Array            | []int                           |
+//  | []uint8               | Uint8Array            | []uint8                         |
+//  | []uint16              | Uint16Array           | []uint16                        |
+//  | []uint32, []uint      | Uint32Array           | []uint                          |
+//  | []float32             | Float32Array          | []float32                       |
+//  | []float64             | Float64Array          | []float64                       |
+//  | all other slices      | Array                 | []interface{}                   |
+//  | arrays                | see slice type        | see slice type                  |
+//  | functions             | Function              | func(...interface{}) *js.Object |
+//  | time.Time             | Date                  | time.Time                       |
+//  | -                     | instanceof Node       | *js.Object                      |
+//  | maps, structs         | instanceof Object     | map[string]interface{}          |
+//
+// Additionally, for a struct containing a *js.Object field, only the content of the field will be passed to JavaScript and vice versa.
+package js
+
+// Object is a container for a native JavaScript object. Calls to its methods are treated specially by GopherJS and translated directly to their JavaScript syntax. A nil pointer to Object is equal to JavaScript's "null". Object can not be used as a map key.
+type Object struct{ object *Object }
+
+// Get returns the object's property with the given key.
+func (o *Object) Get(key string) *Object { return o.object.Get(key) }
+
+// Set assigns the value to the object's property with the given key.
+func (o *Object) Set(key string, value interface{}) { o.object.Set(key, value) }
+
+// Delete removes the object's property with the given key.
+func (o *Object) Delete(key string) { o.object.Delete(key) }
+
+// Length returns the object's "length" property, converted to int.
+func (o *Object) Length() int { return o.object.Length() }
+
+// Index returns the i'th element of an array.
+func (o *Object) Index(i int) *Object { return o.object.Index(i) }
+
+// SetIndex sets the i'th element of an array.
+func (o *Object) SetIndex(i int, value interface{}) { o.object.SetIndex(i, value) }
+
+// Call calls the object's method with the given name.
+func (o *Object) Call(name string, args ...interface{}) *Object { return o.object.Call(name, args...) }
+
+// Invoke calls the object itself. This will fail if it is not a function.
+func (o *Object) Invoke(args ...interface{}) *Object { return o.object.Invoke(args...) }
+
+// New creates a new instance of this type object. This will fail if it not a function (constructor).
+func (o *Object) New(args ...interface{}) *Object { return o.object.New(args...) }
+
+// Bool returns the object converted to bool according to JavaScript type conversions.
+func (o *Object) Bool() bool { return o.object.Bool() }
+
+// String returns the object converted to string according to JavaScript type conversions.
+func (o *Object) String() string { return o.object.String() }
+
+// Int returns the object converted to int according to JavaScript type conversions (parseInt).
+func (o *Object) Int() int { return o.object.Int() }
+
+// Int64 returns the object converted to int64 according to JavaScript type conversions (parseInt).
+func (o *Object) Int64() int64 { return o.object.Int64() }
+
+// Uint64 returns the object converted to uint64 according to JavaScript type conversions (parseInt).
+func (o *Object) Uint64() uint64 { return o.object.Uint64() }
+
+// Float returns the object converted to float64 according to JavaScript type conversions (parseFloat).
+func (o *Object) Float() float64 { return o.object.Float() }
+
+// Interface returns the object converted to interface{}. See table in package comment for details.
+func (o *Object) Interface() interface{} { return o.object.Interface() }
+
+// Unsafe returns the object as an uintptr, which can be converted via unsafe.Pointer. Not intended for public use.
+func (o *Object) Unsafe() uintptr { return o.object.Unsafe() }
+
+// Error encapsulates JavaScript errors. Those are turned into a Go panic and may be recovered, giving an *Error that holds the JavaScript error object.
+type Error struct {
+	*Object
+}
+
+// Error returns the message of the encapsulated JavaScript error object.
+func (err *Error) Error() string {
+	return "JavaScript error: " + err.Get("message").String()
+}
+
+// Stack returns the stack property of the encapsulated JavaScript error object.
+func (err *Error) Stack() string {
+	return err.Get("stack").String()
+}
+
+// Global gives JavaScript's global object ("window" for browsers and "GLOBAL" for Node.js).
+var Global *Object
+
+// Module gives the value of the "module" variable set by Node.js. Hint: Set a module export with 'js.Module.Get("exports").Set("exportName", ...)'.
+var Module *Object
+
+// Undefined gives the JavaScript value "undefined".
+var Undefined *Object
+
+// Debugger gets compiled to JavaScript's "debugger;" statement.
+func Debugger() {}
+
+// InternalObject returns the internal JavaScript object that represents i. Not intended for public use.
+func InternalObject(i interface{}) *Object {
+	return nil
+}
+
+// MakeFunc wraps a function and gives access to the values of JavaScript's "this" and "arguments" keywords.
+func MakeFunc(fn func(this *Object, arguments []*Object) interface{}) *Object {
+	return Global.Call("$makeFunc", InternalObject(fn))
+}
+
+// Keys returns the keys of the given JavaScript object.
+func Keys(o *Object) []string {
+	if o == nil || o == Undefined {
+		return nil
+	}
+	a := Global.Get("Object").Call("keys", o)
+	s := make([]string, a.Length())
+	for i := 0; i < a.Length(); i++ {
+		s[i] = a.Index(i).String()
+	}
+	return s
+}
+
+// MakeWrapper creates a JavaScript object which has wrappers for the exported methods of i. Use explicit getter and setter methods to expose struct fields to JavaScript.
+func MakeWrapper(i interface{}) *Object {
+	v := InternalObject(i)
+	o := Global.Get("Object").New()
+	o.Set("__internal_object__", v)
+	methods := v.Get("constructor").Get("methods")
+	for i := 0; i < methods.Length(); i++ {
+		m := methods.Index(i)
+		if m.Get("pkg").String() != "" { // not exported
+			continue
+		}
+		o.Set(m.Get("name").String(), func(args ...*Object) *Object {
+			return Global.Call("$externalizeFunction", v.Get(m.Get("prop").String()), m.Get("typ"), true).Call("apply", v, args)
+		})
+	}
+	return o
+}
+
+// NewArrayBuffer creates a JavaScript ArrayBuffer from a byte slice.
+func NewArrayBuffer(b []byte) *Object {
+	slice := InternalObject(b)
+	offset := slice.Get("$offset").Int()
+	length := slice.Get("$length").Int()
+	return slice.Get("$array").Get("buffer").Call("slice", offset, offset+length)
+}
+
+// M is a simple map type. It is intended as a shorthand for JavaScript objects (before conversion).
+type M map[string]interface{}
+
+// S is a simple slice type. It is intended as a shorthand for JavaScript arrays (before conversion).
+type S []interface{}
+
+func init() {
+	// avoid dead code elimination
+	e := Error{}
+	_ = e
+}

+ 35 - 0
vendor/golang.org/x/crypto/bcrypt/base64.go

@@ -0,0 +1,35 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcrypt
+
+import "encoding/base64"
+
+const alphabet = "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+
+var bcEncoding = base64.NewEncoding(alphabet)
+
+func base64Encode(src []byte) []byte {
+	n := bcEncoding.EncodedLen(len(src))
+	dst := make([]byte, n)
+	bcEncoding.Encode(dst, src)
+	for dst[n-1] == '=' {
+		n--
+	}
+	return dst[:n]
+}
+
+func base64Decode(src []byte) ([]byte, error) {
+	numOfEquals := 4 - (len(src) % 4)
+	for i := 0; i < numOfEquals; i++ {
+		src = append(src, '=')
+	}
+
+	dst := make([]byte, bcEncoding.DecodedLen(len(src)))
+	n, err := bcEncoding.Decode(dst, src)
+	if err != nil {
+		return nil, err
+	}
+	return dst[:n], nil
+}

+ 294 - 0
vendor/golang.org/x/crypto/bcrypt/bcrypt.go

@@ -0,0 +1,294 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bcrypt implements Provos and Mazières's bcrypt adaptive hashing
+// algorithm. See http://www.usenix.org/event/usenix99/provos/provos.pdf
+package bcrypt // import "golang.org/x/crypto/bcrypt"
+
+// The code is a port of Provos and Mazières's C implementation.
+import (
+	"crypto/rand"
+	"crypto/subtle"
+	"errors"
+	"fmt"
+	"golang.org/x/crypto/blowfish"
+	"io"
+	"strconv"
+)
+
+const (
+	MinCost     int = 4  // the minimum allowable cost as passed in to GenerateFromPassword
+	MaxCost     int = 31 // the maximum allowable cost as passed in to GenerateFromPassword
+	DefaultCost int = 10 // the cost that will actually be set if a cost below MinCost is passed into GenerateFromPassword
+)
+
+// The error returned from CompareHashAndPassword when a password and hash do
+// not match.
+var ErrMismatchedHashAndPassword = errors.New("crypto/bcrypt: hashedPassword is not the hash of the given password")
+
+// The error returned from CompareHashAndPassword when a hash is too short to
+// be a bcrypt hash.
+var ErrHashTooShort = errors.New("crypto/bcrypt: hashedSecret too short to be a bcrypted password")
+
+// The error returned from CompareHashAndPassword when a hash was created with
+// a bcrypt algorithm newer than this implementation.
+type HashVersionTooNewError byte
+
+func (hv HashVersionTooNewError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt algorithm version '%c' requested is newer than current version '%c'", byte(hv), majorVersion)
+}
+
+// The error returned from CompareHashAndPassword when a hash starts with something other than '$'
+type InvalidHashPrefixError byte
+
+func (ih InvalidHashPrefixError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: bcrypt hashes must start with '$', but hashedSecret started with '%c'", byte(ih))
+}
+
+type InvalidCostError int
+
+func (ic InvalidCostError) Error() string {
+	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
+}
+
+const (
+	majorVersion       = '2'
+	minorVersion       = 'a'
+	maxSaltSize        = 16
+	maxCryptedHashSize = 23
+	encodedSaltSize    = 22
+	encodedHashSize    = 31
+	minHashSize        = 59
+)
+
+// magicCipherData is an IV for the 64 Blowfish encryption calls in
+// bcrypt(). It's the string "OrpheanBeholderScryDoubt" in big-endian bytes.
+var magicCipherData = []byte{
+	0x4f, 0x72, 0x70, 0x68,
+	0x65, 0x61, 0x6e, 0x42,
+	0x65, 0x68, 0x6f, 0x6c,
+	0x64, 0x65, 0x72, 0x53,
+	0x63, 0x72, 0x79, 0x44,
+	0x6f, 0x75, 0x62, 0x74,
+}
+
+type hashed struct {
+	hash  []byte
+	salt  []byte
+	cost  int // allowed range is MinCost to MaxCost
+	major byte
+	minor byte
+}
+
+// GenerateFromPassword returns the bcrypt hash of the password at the given
+// cost. If the cost given is less than MinCost, the cost will be set to
+// DefaultCost, instead. Use CompareHashAndPassword, as defined in this package,
+// to compare the returned hashed password with its cleartext version.
+func GenerateFromPassword(password []byte, cost int) ([]byte, error) {
+	p, err := newFromPassword(password, cost)
+	if err != nil {
+		return nil, err
+	}
+	return p.Hash(), nil
+}
+
+// CompareHashAndPassword compares a bcrypt hashed password with its possible
+// plaintext equivalent. Returns nil on success, or an error on failure.
+func CompareHashAndPassword(hashedPassword, password []byte) error {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return err
+	}
+
+	otherHash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return err
+	}
+
+	otherP := &hashed{otherHash, p.salt, p.cost, p.major, p.minor}
+	if subtle.ConstantTimeCompare(p.Hash(), otherP.Hash()) == 1 {
+		return nil
+	}
+
+	return ErrMismatchedHashAndPassword
+}
+
+// Cost returns the hashing cost used to create the given hashed
+// password. When, in the future, the hashing cost of a password system needs
+// to be increased in order to adjust for greater computational power, this
+// function allows one to establish which passwords need to be updated.
+func Cost(hashedPassword []byte) (int, error) {
+	p, err := newFromHash(hashedPassword)
+	if err != nil {
+		return 0, err
+	}
+	return p.cost, nil
+}
+
+func newFromPassword(password []byte, cost int) (*hashed, error) {
+	if cost < MinCost {
+		cost = DefaultCost
+	}
+	p := new(hashed)
+	p.major = majorVersion
+	p.minor = minorVersion
+
+	err := checkCost(cost)
+	if err != nil {
+		return nil, err
+	}
+	p.cost = cost
+
+	unencodedSalt := make([]byte, maxSaltSize)
+	_, err = io.ReadFull(rand.Reader, unencodedSalt)
+	if err != nil {
+		return nil, err
+	}
+
+	p.salt = base64Encode(unencodedSalt)
+	hash, err := bcrypt(password, p.cost, p.salt)
+	if err != nil {
+		return nil, err
+	}
+	p.hash = hash
+	return p, err
+}
+
+func newFromHash(hashedSecret []byte) (*hashed, error) {
+	if len(hashedSecret) < minHashSize {
+		return nil, ErrHashTooShort
+	}
+	p := new(hashed)
+	n, err := p.decodeVersion(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+	n, err = p.decodeCost(hashedSecret)
+	if err != nil {
+		return nil, err
+	}
+	hashedSecret = hashedSecret[n:]
+
+	// The "+2" is here because we'll have to append at most 2 '=' to the salt
+	// when base64 decoding it in expensiveBlowfishSetup().
+	p.salt = make([]byte, encodedSaltSize, encodedSaltSize+2)
+	copy(p.salt, hashedSecret[:encodedSaltSize])
+
+	hashedSecret = hashedSecret[encodedSaltSize:]
+	p.hash = make([]byte, len(hashedSecret))
+	copy(p.hash, hashedSecret)
+
+	return p, nil
+}
+
+func bcrypt(password []byte, cost int, salt []byte) ([]byte, error) {
+	cipherData := make([]byte, len(magicCipherData))
+	copy(cipherData, magicCipherData)
+
+	c, err := expensiveBlowfishSetup(password, uint32(cost), salt)
+	if err != nil {
+		return nil, err
+	}
+
+	for i := 0; i < 24; i += 8 {
+		for j := 0; j < 64; j++ {
+			c.Encrypt(cipherData[i:i+8], cipherData[i:i+8])
+		}
+	}
+
+	// Bug compatibility with C bcrypt implementations. We only encode 23 of
+	// the 24 bytes encrypted.
+	hsh := base64Encode(cipherData[:maxCryptedHashSize])
+	return hsh, nil
+}
+
+func expensiveBlowfishSetup(key []byte, cost uint32, salt []byte) (*blowfish.Cipher, error) {
+
+	csalt, err := base64Decode(salt)
+	if err != nil {
+		return nil, err
+	}
+
+	// Bug compatibility with C bcrypt implementations. They use the trailing
+	// NULL in the key string during expansion.
+	ckey := append(key, 0)
+
+	c, err := blowfish.NewSaltedCipher(ckey, csalt)
+	if err != nil {
+		return nil, err
+	}
+
+	var i, rounds uint64
+	rounds = 1 << cost
+	for i = 0; i < rounds; i++ {
+		blowfish.ExpandKey(ckey, c)
+		blowfish.ExpandKey(csalt, c)
+	}
+
+	return c, nil
+}
+
+func (p *hashed) Hash() []byte {
+	arr := make([]byte, 60)
+	arr[0] = '$'
+	arr[1] = p.major
+	n := 2
+	if p.minor != 0 {
+		arr[2] = p.minor
+		n = 3
+	}
+	arr[n] = '$'
+	n += 1
+	copy(arr[n:], []byte(fmt.Sprintf("%02d", p.cost)))
+	n += 2
+	arr[n] = '$'
+	n += 1
+	copy(arr[n:], p.salt)
+	n += encodedSaltSize
+	copy(arr[n:], p.hash)
+	n += encodedHashSize
+	return arr[:n]
+}
+
+func (p *hashed) decodeVersion(sbytes []byte) (int, error) {
+	if sbytes[0] != '$' {
+		return -1, InvalidHashPrefixError(sbytes[0])
+	}
+	if sbytes[1] > majorVersion {
+		return -1, HashVersionTooNewError(sbytes[1])
+	}
+	p.major = sbytes[1]
+	n := 3
+	if sbytes[2] != '$' {
+		p.minor = sbytes[2]
+		n++
+	}
+	return n, nil
+}
+
+// sbytes should begin where decodeVersion left off.
+func (p *hashed) decodeCost(sbytes []byte) (int, error) {
+	cost, err := strconv.Atoi(string(sbytes[0:2]))
+	if err != nil {
+		return -1, err
+	}
+	err = checkCost(cost)
+	if err != nil {
+		return -1, err
+	}
+	p.cost = cost
+	return 3, nil
+}
+
+func (p *hashed) String() string {
+	return fmt.Sprintf("&{hash: %#v, salt: %#v, cost: %d, major: %c, minor: %c}", string(p.hash), p.salt, p.cost, p.major, p.minor)
+}
+
+func checkCost(cost int) error {
+	if cost < MinCost || cost > MaxCost {
+		return InvalidCostError(cost)
+	}
+	return nil
+}

+ 159 - 0
vendor/golang.org/x/crypto/blowfish/block.go

@@ -0,0 +1,159 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package blowfish
+
+// getNextWord returns the next big-endian uint32 value from the byte slice
+// at the given position in a circular manner, updating the position.
+func getNextWord(b []byte, pos *int) uint32 {
+	var w uint32
+	j := *pos
+	for i := 0; i < 4; i++ {
+		w = w<<8 | uint32(b[j])
+		j++
+		if j >= len(b) {
+			j = 0
+		}
+	}
+	*pos = j
+	return w
+}
+
+// ExpandKey performs a key expansion on the given *Cipher. Specifically, it
+// performs the Blowfish algorithm's key schedule which sets up the *Cipher's
+// pi and substitution tables for calls to Encrypt. This is used, primarily,
+// by the bcrypt package to reuse the Blowfish key schedule during its
+// set up. It's unlikely that you need to use this directly.
+func ExpandKey(key []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		// Using inlined getNextWord for performance.
+		var d uint32
+		for k := 0; k < 4; k++ {
+			d = d<<8 | uint32(key[j])
+			j++
+			if j >= len(key) {
+				j = 0
+			}
+		}
+		c.p[i] ^= d
+	}
+
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+	for i := 0; i < 256; i += 2 {
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+// This is similar to ExpandKey, but folds the salt during the key
+// schedule. While ExpandKey is essentially expandKeyWithSalt with an all-zero
+// salt passed in, reusing ExpandKey turns out to be a place of inefficiency
+// and specializing it here is useful.
+func expandKeyWithSalt(key []byte, salt []byte, c *Cipher) {
+	j := 0
+	for i := 0; i < 18; i++ {
+		c.p[i] ^= getNextWord(key, &j)
+	}
+
+	j = 0
+	var l, r uint32
+	for i := 0; i < 18; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.p[i], c.p[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s0[i], c.s0[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s1[i], c.s1[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s2[i], c.s2[i+1] = l, r
+	}
+
+	for i := 0; i < 256; i += 2 {
+		l ^= getNextWord(salt, &j)
+		r ^= getNextWord(salt, &j)
+		l, r = encryptBlock(l, r, c)
+		c.s3[i], c.s3[i+1] = l, r
+	}
+}
+
+func encryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[0]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[1]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[2]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[3]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[4]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[5]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[6]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[7]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[8]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[9]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[10]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[11]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[12]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[13]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[14]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[15]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[16]
+	xr ^= c.p[17]
+	return xr, xl
+}
+
+func decryptBlock(l, r uint32, c *Cipher) (uint32, uint32) {
+	xl, xr := l, r
+	xl ^= c.p[17]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[16]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[15]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[14]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[13]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[12]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[11]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[10]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[9]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[8]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[7]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[6]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[5]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[4]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[3]
+	xr ^= ((c.s0[byte(xl>>24)] + c.s1[byte(xl>>16)]) ^ c.s2[byte(xl>>8)]) + c.s3[byte(xl)] ^ c.p[2]
+	xl ^= ((c.s0[byte(xr>>24)] + c.s1[byte(xr>>16)]) ^ c.s2[byte(xr>>8)]) + c.s3[byte(xr)] ^ c.p[1]
+	xr ^= c.p[0]
+	return xr, xl
+}

+ 91 - 0
vendor/golang.org/x/crypto/blowfish/cipher.go

@@ -0,0 +1,91 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package blowfish implements Bruce Schneier's Blowfish encryption algorithm.
+package blowfish // import "golang.org/x/crypto/blowfish"
+
+// The code is a port of Bruce Schneier's C implementation.
+// See http://www.schneier.com/blowfish.html.
+
+import "strconv"
+
+// The Blowfish block size in bytes.
+const BlockSize = 8
+
+// A Cipher is an instance of Blowfish encryption using a particular key.
+type Cipher struct {
+	p              [18]uint32
+	s0, s1, s2, s3 [256]uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+	return "crypto/blowfish: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a Cipher.
+// The key argument should be the Blowfish key, from 1 to 56 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+	var result Cipher
+	if k := len(key); k < 1 || k > 56 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	ExpandKey(key, &result)
+	return &result, nil
+}
+
+// NewSaltedCipher creates a returns a Cipher that folds a salt into its key
+// schedule. For most purposes, NewCipher, instead of NewSaltedCipher, is
+// sufficient and desirable. For bcrypt compatibility, the key can be over 56
+// bytes.
+func NewSaltedCipher(key, salt []byte) (*Cipher, error) {
+	if len(salt) == 0 {
+		return NewCipher(key)
+	}
+	var result Cipher
+	if k := len(key); k < 1 {
+		return nil, KeySizeError(k)
+	}
+	initCipher(&result)
+	expandKeyWithSalt(key, salt, &result)
+	return &result, nil
+}
+
+// BlockSize returns the Blowfish block size, 8 bytes.
+// It is necessary to satisfy the Block interface in the
+// package "crypto/cipher".
+func (c *Cipher) BlockSize() int { return BlockSize }
+
+// Encrypt encrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+// Note that for amounts of data larger than a block,
+// it is not safe to just call Encrypt on successive blocks;
+// instead, use an encryption mode like CBC (see crypto/cipher/cbc.go).
+func (c *Cipher) Encrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = encryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+// Decrypt decrypts the 8-byte buffer src using the key k
+// and stores the result in dst.
+func (c *Cipher) Decrypt(dst, src []byte) {
+	l := uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
+	r := uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
+	l, r = decryptBlock(l, r, c)
+	dst[0], dst[1], dst[2], dst[3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
+	dst[4], dst[5], dst[6], dst[7] = byte(r>>24), byte(r>>16), byte(r>>8), byte(r)
+}
+
+func initCipher(c *Cipher) {
+	copy(c.p[0:], p[0:])
+	copy(c.s0[0:], s0[0:])
+	copy(c.s1[0:], s1[0:])
+	copy(c.s2[0:], s2[0:])
+	copy(c.s3[0:], s3[0:])
+}

+ 199 - 0
vendor/golang.org/x/crypto/blowfish/const.go

@@ -0,0 +1,199 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The startup permutation array and substitution boxes.
+// They are the hexadecimal digits of PI; see:
+// http://www.schneier.com/code/constants.txt.
+
+package blowfish
+
+var s0 = [256]uint32{
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
+	0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
+	0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
+	0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
+	0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
+	0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
+	0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
+	0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
+	0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
+	0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
+	0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
+	0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
+	0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
+	0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
+	0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
+	0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
+	0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
+	0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
+	0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
+	0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
+	0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
+	0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+}
+
+var s1 = [256]uint32{
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
+	0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
+	0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
+	0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
+	0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
+	0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
+	0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
+	0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
+	0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
+	0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
+	0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
+	0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
+	0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
+	0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
+	0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
+	0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
+	0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
+	0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
+	0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
+	0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
+	0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
+	0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+}
+
+var s2 = [256]uint32{
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
+	0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
+	0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
+	0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
+	0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
+	0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
+	0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
+	0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
+	0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
+	0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
+	0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
+	0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
+	0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
+	0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
+	0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
+	0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
+	0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
+	0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
+	0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
+	0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
+	0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
+	0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+}
+
+var s3 = [256]uint32{
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
+	0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
+	0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
+	0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
+	0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
+	0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
+	0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
+	0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
+	0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
+	0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
+	0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
+	0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
+	0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
+	0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
+	0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
+	0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
+	0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
+	0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
+	0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
+	0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
+	0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
+	0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+}
+
+var p = [18]uint32{
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
+	0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
+}

+ 31 - 1
vendor/vendor.json

@@ -2,6 +2,18 @@
 	"comment": "",
 	"ignore": "test",
 	"package": [
+		{
+			"checksumSHA1": "/OCenqqlNlqcINpnIQwK6Givd+w=",
+			"path": "github.com/G-Node/git-module",
+			"revision": "69dde43afd4427d634e702c2059a96d99b5af1c2",
+			"revisionTime": "2017-07-11T12:59:03Z"
+		},
+		{
+			"checksumSHA1": "vjZdri9BVeaL5W9Py2wdIAj35qQ=",
+			"path": "github.com/G-Node/go-annex",
+			"revision": "3cd728fddc604d7cd4b9b74ff6780a9d67aa1d12",
+			"revisionTime": "2017-07-11T13:07:39Z"
+		},
 		{
 			"checksumSHA1": "IyfS7Rbl6OgR83QR7TOfKdDCq+M=",
 			"path": "github.com/Unknwon/cae",
@@ -206,6 +218,12 @@
 			"revision": "95be6356811a6fbd4c2981713236971a3ccbb33a",
 			"revisionTime": "2017-03-01T03:54:11Z"
 		},
+		{
+			"checksumSHA1": "yIkYzW7bzAD81zHyuCNmEj4+oxQ=",
+			"path": "github.com/gopherjs/gopherjs/js",
+			"revision": "2b1d432c8a82c9bff0b0baffaeb3ec6e92974112",
+			"revisionTime": "2017-07-02T15:34:43Z"
+		},
 		{
 			"checksumSHA1": "MLO0PyrK2MUO6A7Z9PxWuu43C/A=",
 			"path": "github.com/issue9/identicon",
@@ -386,6 +404,18 @@
 			"revision": "b6061c464d493dd94985211595687c862a0dd0bc",
 			"revisionTime": "2016-11-19T19:05:28Z"
 		},
+		{
+			"checksumSHA1": "vE43s37+4CJ2CDU6TlOUOYE0K9c=",
+			"path": "golang.org/x/crypto/bcrypt",
+			"revision": "c367d6eeb7c6158125f2f47e049f7eb7e251c09a",
+			"revisionTime": "2016-10-18T21:00:36Z"
+		},
+		{
+			"checksumSHA1": "JsJdKXhz87gWenMwBeejTOeNE7k=",
+			"path": "golang.org/x/crypto/blowfish",
+			"revision": "c367d6eeb7c6158125f2f47e049f7eb7e251c09a",
+			"revisionTime": "2016-10-18T21:00:36Z"
+		},
 		{
 			"checksumSHA1": "dwOedwBJ1EIK9+S3t108Bx054Y8=",
 			"path": "golang.org/x/crypto/curve25519",
@@ -609,5 +639,5 @@
 			"revisionTime": "2014-12-09T11:07:59Z"
 		}
 	],
-	"rootPath": "github.com/gogits/gogs"
+	"rootPath": "github.com/G-Node/gogs"
 }

+ 628 - 0
vendor/vendor.json.orig

@@ -0,0 +1,628 @@
+{
+	"comment": "",
+	"ignore": "test",
+	"package": [
+		{
+<<<<<<< HEAD
+=======
+			"checksumSHA1": "/OCenqqlNlqcINpnIQwK6Givd+w=",
+			"path": "github.com/G-Node/git-module",
+			"revision": "69dde43afd4427d634e702c2059a96d99b5af1c2",
+			"revisionTime": "2017-07-11T12:59:03Z"
+		},
+		{
+			"checksumSHA1": "vjZdri9BVeaL5W9Py2wdIAj35qQ=",
+			"path": "github.com/G-Node/go-annex",
+			"revision": "3cd728fddc604d7cd4b9b74ff6780a9d67aa1d12",
+			"revisionTime": "2017-07-11T13:07:39Z"
+		},
+		{
+>>>>>>> 524ff0b... [vendor] update go-annex
+			"checksumSHA1": "IyfS7Rbl6OgR83QR7TOfKdDCq+M=",
+			"path": "github.com/Unknwon/cae",
+			"revision": "c6aac99ea2cae2ebaf23f26f76b04fe3fcfc9f8c",
+			"revisionTime": "2016-07-15T03:28:08Z"
+		},
+		{
+			"checksumSHA1": "NqlZvp3s2Z8jy1X9HpARViZ/hhY=",
+			"path": "github.com/Unknwon/cae/zip",
+			"revision": "c6aac99ea2cae2ebaf23f26f76b04fe3fcfc9f8c",
+			"revisionTime": "2016-07-15T03:28:08Z"
+		},
+		{
+			"checksumSHA1": "7HXb3cry6luicWeJM9Uxwzfo9Rs=",
+			"path": "github.com/Unknwon/com",
+			"revision": "0db4a625e949e956314d7d1adea9bf82384cc10c",
+			"revisionTime": "2017-02-13T07:20:14Z"
+		},
+		{
+			"checksumSHA1": "qbYhQkK6nb2oZ9OOyyuQpWD9fXY=",
+			"path": "github.com/Unknwon/i18n",
+			"revision": "e0eb0cef13c5eadc03d6993f3069c72e566004b7",
+			"revisionTime": "2017-02-18T21:29:01Z"
+		},
+		{
+			"checksumSHA1": "VI3Bz1L335gsrP1ZF0v3f+WWy3M=",
+			"path": "github.com/Unknwon/paginater",
+			"revision": "7650849cd241779b451f30767bcb046ca13648b0",
+			"revisionTime": "2017-02-05T23:42:31Z"
+		},
+		{
+			"checksumSHA1": "tLl952GRIVsso2Pk/IH3cMJaK8E=",
+			"path": "github.com/boombuler/barcode",
+			"revision": "0dc17c9053c4956f07a6db58b2863924fe03b643",
+			"revisionTime": "2017-04-03T18:34:37Z"
+		},
+		{
+			"checksumSHA1": "tbwzn+sWiZv6veyXae3qRfTjlcQ=",
+			"path": "github.com/boombuler/barcode/qr",
+			"revision": "0dc17c9053c4956f07a6db58b2863924fe03b643",
+			"revisionTime": "2017-04-03T18:34:37Z"
+		},
+		{
+			"checksumSHA1": "axe0OTdOjYa+XKDUYqzOv7FGaWo=",
+			"path": "github.com/boombuler/barcode/utils",
+			"revision": "0dc17c9053c4956f07a6db58b2863924fe03b643",
+			"revisionTime": "2017-04-03T18:34:37Z"
+		},
+		{
+			"checksumSHA1": "fNAC4qgZDqF3kxq74/yyk3PWdy8=",
+			"path": "github.com/bradfitz/gomemcache/memcache",
+			"revision": "fb1f79c6b65acda83063cbc69f6bba1522558bfc",
+			"revisionTime": "2016-01-17T19:21:50Z"
+		},
+		{
+			"checksumSHA1": "NKoZRlZix5wzCfN0rTg29GtKZRU=",
+			"path": "github.com/chaseadamsio/goorgeous",
+			"revision": "677defd0e024333503d8c946dd4ba3f32ad3e5d2",
+			"revisionTime": "2017-04-27T12:50:10Z"
+		},
+		{
+			"checksumSHA1": "HG4+dlJq5h+07VI1rOlpc5KBlfg=",
+			"path": "github.com/denisenkom/go-mssqldb",
+			"revision": "9e40d9d5d325edfaa84d3374bfde6e1adce02d58",
+			"revisionTime": "2017-01-17T17:39:00Z"
+		},
+		{
+			"checksumSHA1": "XEBl9iQQvfXNlwCSzyAOCqAlYEA=",
+			"path": "github.com/fatih/color",
+			"revision": "42c364ba490082e4815b5222728711b3440603eb",
+			"revisionTime": "2017-01-13T15:16:12Z"
+		},
+		{
+			"checksumSHA1": "J0tcl2i76AQvMio9MWNQaucepYA=",
+			"path": "github.com/go-macaron/binding",
+			"revision": "ac54ee249c27dca7e76fad851a4a04b73bd1b183",
+			"revisionTime": "2017-06-11T06:58:19Z"
+		},
+		{
+			"checksumSHA1": "6pSblXcT+pZJWhPCEyLZONiQUHg=",
+			"path": "github.com/go-macaron/cache",
+			"revision": "56173531277692bc2925924d51fda1cd0a6b8178",
+			"revisionTime": "2015-10-13T08:11:02Z"
+		},
+		{
+			"checksumSHA1": "pvtjguZ5Ki0KbzOBRM1/Jh31klw=",
+			"path": "github.com/go-macaron/cache/memcache",
+			"revision": "56173531277692bc2925924d51fda1cd0a6b8178",
+			"revisionTime": "2015-10-13T08:11:02Z"
+		},
+		{
+			"checksumSHA1": "lfJWq+CuwU5GAPtsSx3mRi4LOiw=",
+			"path": "github.com/go-macaron/cache/redis",
+			"revision": "56173531277692bc2925924d51fda1cd0a6b8178",
+			"revisionTime": "2015-10-13T08:11:02Z"
+		},
+		{
+			"checksumSHA1": "kWnClaQsy/2YLvx2SrSUGgSyhzk=",
+			"path": "github.com/go-macaron/captcha",
+			"revision": "a9d45b762e2537878323cd8a4147644378f09be1",
+			"revisionTime": "2017-03-28T22:26:02Z"
+		},
+		{
+			"checksumSHA1": "i52HJHpyI3avut3QAIrrD0h7gmY=",
+			"path": "github.com/go-macaron/csrf",
+			"revision": "6a9a7df172cc1fcd81e4585f44b09200b6087cc0",
+			"revisionTime": "2016-03-13T01:51:27Z"
+		},
+		{
+			"checksumSHA1": "Rp4MJ0xFAy00EC0zlnwCpTEdYY8=",
+			"path": "github.com/go-macaron/gzip",
+			"revision": "cad1c6580a07c56f5f6bc52d66002a05985c5854",
+			"revisionTime": "2016-02-22T04:36:47Z"
+		},
+		{
+			"checksumSHA1": "YMALCXSAIHZU9/K6EDI/kNTq3Hk=",
+			"path": "github.com/go-macaron/i18n",
+			"revision": "ef57533c3b0fc2d8581deda14937e52f11a203ab",
+			"revisionTime": "2016-06-12T09:28:37Z"
+		},
+		{
+			"checksumSHA1": "y0olVbiMQ6/UOa/eh52XYnies90=",
+			"path": "github.com/go-macaron/inject",
+			"revision": "d8a0b8677191f4380287cfebd08e462217bac7ad",
+			"revisionTime": "2016-06-27T17:00:12Z"
+		},
+		{
+			"checksumSHA1": "gO0dj0NqsmBTkf4D0JzJDtOEx+U=",
+			"path": "github.com/go-macaron/session",
+			"revision": "b8e286a0dba8f4999042d6b258daf51b31d08938",
+			"revisionTime": "2017-03-20T17:22:09Z"
+		},
+		{
+			"checksumSHA1": "jVW5CmzplA0UDjai0AFYJFVXAJk=",
+			"path": "github.com/go-macaron/session/redis",
+			"revision": "66031fcb37a0fff002a1f028eb0b3a815c78306b",
+			"revisionTime": "2015-10-14T03:41:01Z"
+		},
+		{
+			"checksumSHA1": "VMRkwnbl0mKWWvK/62CnIlv1oOg=",
+			"path": "github.com/go-macaron/toolbox",
+			"revision": "6766b8f16d1b135b250f09ba4dc4e24ab65b1107",
+			"revisionTime": "2017-02-20T18:37:56Z"
+		},
+		{
+			"checksumSHA1": "jEXpLrWXoQvH/zk1lW5Si0swr6Y=",
+			"path": "github.com/go-sql-driver/mysql",
+			"revision": "0b58b37b664c21f3010e836f1b931e1d0b0b0685",
+			"revisionTime": "2016-08-02T11:38:42Z"
+		},
+		{
+			"checksumSHA1": "9SXbj96wb1PgppBZzxMIN0axbFQ=",
+			"path": "github.com/go-xorm/builder",
+			"revision": "c8871c857d2555fbfbd8524f895be5386d3d8836",
+			"revisionTime": "2017-05-19T03:21:30Z"
+		},
+		{
+			"checksumSHA1": "GnWfEqqhYT5MsxzlB6bRESmkDvM=",
+			"path": "github.com/go-xorm/core",
+			"revision": "6c9f9bf3130d143937e4adcef1cf1bb9f6899260",
+			"revisionTime": "2017-05-03T12:16:46Z"
+		},
+		{
+			"checksumSHA1": "UN8r+3fuSzXJ1tXCe+M8g5eRpOI=",
+			"path": "github.com/go-xorm/xorm",
+			"revision": "8a877636fdbbb0f7133b158fe5cde3588464b035",
+			"revisionTime": "2017-06-06T06:54:59Z"
+		},
+		{
+			"checksumSHA1": "1ft/4j5MFa7C9dPI9whL03HSUzk=",
+			"path": "github.com/gogits/chardet",
+			"revision": "2404f777256163ea3eadb273dada5dcb037993c0",
+			"revisionTime": "2015-01-15T10:35:09Z"
+		},
+		{
+			"checksumSHA1": "fswdf/juszifcFH8ghXW6EM2PDs=",
+			"path": "github.com/gogits/cron",
+			"revision": "7f3990acf1833faa5ebd0e86f0a4c72a4b5eba3c",
+			"revisionTime": "2016-08-10T03:50:02Z"
+		},
+		{
+			"checksumSHA1": "kPsa/ri8Vh9yHG8LQYgnH2Xa6YY=",
+			"path": "github.com/gogits/git-module",
+			"revision": "1de103dca47a72afccccb4ccd6085110874f3551",
+			"revisionTime": "2017-06-08T20:55:22Z"
+		},
+		{
+			"checksumSHA1": "GBfb+meRaVNarQavLB/bzbDoBtY=",
+			"path": "github.com/gogits/go-gogs-client",
+			"revision": "bbae6af45f087cf346c09a510412c47e7739b15f",
+			"revisionTime": "2017-06-02T18:25:02Z"
+		},
+		{
+			"checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=",
+			"path": "github.com/gogits/go-libravatar",
+			"revision": "cd1abbd55d09b793672732a7a1dfdaa12a40dfd0",
+			"revisionTime": "2016-11-20T02:51:54Z"
+		},
+		{
+			"checksumSHA1": "cccKtXG5TiCiCT9JA85slbJokfw=",
+			"path": "github.com/gogits/minwinsvc",
+			"revision": "95be6356811a6fbd4c2981713236971a3ccbb33a",
+			"revisionTime": "2017-03-01T03:54:11Z"
+		},
+		{
+			"checksumSHA1": "MLO0PyrK2MUO6A7Z9PxWuu43C/A=",
+			"path": "github.com/issue9/identicon",
+			"revision": "d36b54562f4cf70c83653e13dc95c220c79ef521",
+			"revisionTime": "2016-03-20T06:51:30Z"
+		},
+		{
+			"checksumSHA1": "ItB3fp9m2Q0Sn7IM10f3h6HO5rs=",
+			"path": "github.com/jaytaylor/html2text",
+			"revision": "8fb95d837f7d6db1913fecfd7bcc5333e6499596",
+			"revisionTime": "2016-09-23T19:14:38Z"
+		},
+		{
+			"checksumSHA1": "tewA7jXVGCw1zb5mA0BDecWi4iQ=",
+			"path": "github.com/jtolds/gls",
+			"revision": "8ddce2a84170772b95dd5d576c48d517b22cac63",
+			"revisionTime": "2016-01-05T22:08:40Z"
+		},
+		{
+			"checksumSHA1": "vfzz7zTL9TZLpFO7NC1H6/Du3+s=",
+			"path": "github.com/klauspost/compress/flate",
+			"revision": "e3b7981a12dd3cab49afa1d3a50e715846f23732",
+			"revisionTime": "2016-11-06T14:34:36Z"
+		},
+		{
+			"checksumSHA1": "V1lQwkoDR1fPmZBSgkmZjgZofeU=",
+			"path": "github.com/klauspost/compress/gzip",
+			"revision": "e3b7981a12dd3cab49afa1d3a50e715846f23732",
+			"revisionTime": "2016-11-06T14:34:36Z"
+		},
+		{
+			"checksumSHA1": "iKPMvbAueGfdyHcWCgzwKzm8WVo=",
+			"path": "github.com/klauspost/cpuid",
+			"revision": "09cded8978dc9e80714c4d85b0322337b0a1e5e0",
+			"revisionTime": "2016-03-02T07:53:16Z"
+		},
+		{
+			"checksumSHA1": "BM6ZlNJmtKy3GBoWwg2X55gnZ4A=",
+			"path": "github.com/klauspost/crc32",
+			"revision": "cb6bfca970f6908083f26f39a79009d608efd5cd",
+			"revisionTime": "2016-10-16T15:41:25Z"
+		},
+		{
+			"checksumSHA1": "88ochAZ1SsbAH6DgBQ5eTUChFE0=",
+			"path": "github.com/lib/pq",
+			"revision": "ae8357db35d721c58dcdc911318b55bef6b1b001",
+			"revisionTime": "2016-10-14T01:16:34Z"
+		},
+		{
+			"checksumSHA1": "xppHi82MLqVx1eyQmbhTesAEjx8=",
+			"path": "github.com/lib/pq/oid",
+			"revision": "ae8357db35d721c58dcdc911318b55bef6b1b001",
+			"revisionTime": "2016-10-14T01:16:34Z"
+		},
+		{
+			"checksumSHA1": "I4njd26dG5hxFT2nawuByM4pxzY=",
+			"path": "github.com/mattn/go-colorable",
+			"revision": "d228849504861217f796da67fae4f6e347643f15",
+			"revisionTime": "2016-11-03T16:00:40Z"
+		},
+		{
+			"checksumSHA1": "xZuhljnmBysJPta/lMyYmJdujCg=",
+			"path": "github.com/mattn/go-isatty",
+			"revision": "30a891c33c7cde7b02a981314b4228ec99380cca",
+			"revisionTime": "2016-11-23T14:36:37Z"
+		},
+		{
+			"checksumSHA1": "9NOEwusDSfhREf0ix7ULW9f3hhw=",
+			"path": "github.com/mattn/go-sqlite3",
+			"revision": "2d44decb4941c9cdf72c22297b7890faf7da9bcb",
+			"revisionTime": "2016-12-15T04:15:57Z"
+		},
+		{
+			"checksumSHA1": "wf7QK5pRmd4/NORvkMK7uflvcO0=",
+			"path": "github.com/mcuadros/go-version",
+			"revision": "257f7b9a7d87427c8d7f89469a5958d57f8abd7c",
+			"revisionTime": "2016-11-05T18:36:18Z"
+		},
+		{
+			"checksumSHA1": "r1klEIiloTrSYFv3cjaJcPHLkLo=",
+			"path": "github.com/microcosm-cc/bluemonday",
+			"revision": "f77f16ffc87a6a58814e64ae72d55f9c41374e6d",
+			"revisionTime": "2016-10-12T08:37:05Z"
+		},
+		{
+			"checksumSHA1": "lfOuMiAdiqc/dalUSBTvD5ZMSzA=",
+			"path": "github.com/msteinert/pam",
+			"revision": "02ccfbfaf0cc627aa3aec8ef7ed5cfeec5b43f63",
+			"revisionTime": "2015-12-04T16:05:44Z"
+		},
+		{
+			"checksumSHA1": "r5eQHkttko6kxroDEENXbmXKrSs=",
+			"path": "github.com/nfnt/resize",
+			"revision": "891127d8d1b52734debe1b3c3d7e747502b6c366",
+			"revisionTime": "2016-07-24T20:39:20Z"
+		},
+		{
+			"checksumSHA1": "woY3inKe+d7B1jPTFxVKNCCFH9c=",
+			"path": "github.com/pquerna/otp",
+			"revision": "9e1935374bc73ffe011187dafed51a412b90fe43",
+			"revisionTime": "2017-02-23T01:06:52Z"
+		},
+		{
+			"checksumSHA1": "xo32aXW4ZXXRHJ/9E6m10vXJZAo=",
+			"path": "github.com/pquerna/otp/hotp",
+			"revision": "9e1935374bc73ffe011187dafed51a412b90fe43",
+			"revisionTime": "2017-02-23T01:06:52Z"
+		},
+		{
+			"checksumSHA1": "Ie55pTQw1rnOZ8KDekSDXUWDT1I=",
+			"path": "github.com/pquerna/otp/totp",
+			"revision": "9e1935374bc73ffe011187dafed51a412b90fe43",
+			"revisionTime": "2017-02-23T01:06:52Z"
+		},
+		{
+			"checksumSHA1": "c7jHQZk5ZEsFR9EXsWJXkszPBZA=",
+			"path": "github.com/russross/blackfriday",
+			"revision": "5f33e7b7878355cd2b7e6b8eefc48a5472c69f70",
+			"revisionTime": "2016-10-03T16:27:22Z"
+		},
+		{
+			"checksumSHA1": "zmC8/3V4ls53DJlNTKDZwPSC/dA=",
+			"path": "github.com/satori/go.uuid",
+			"revision": "b061729afc07e77a8aa4fad0a2fd840958f1942a",
+			"revisionTime": "2016-09-27T10:08:44Z"
+		},
+		{
+			"checksumSHA1": "UzQgUwcGo3qDLKJ1fYttO/DYCwU=",
+			"path": "github.com/sergi/go-diff/diffmatchpatch",
+			"revision": "ce4a6e0e61d6908298eed511fc0683062d4c7f3b",
+			"revisionTime": "2016-09-28T15:06:20Z"
+		},
+		{
+			"checksumSHA1": "kbgJvKG3NRoqU91rYnXGnyR+8HQ=",
+			"path": "github.com/shurcooL/sanitized_anchor_name",
+			"revision": "1dba4b3954bc059efc3991ec364f9f9a35f597d2",
+			"revisionTime": "2016-09-18T04:11:01Z"
+		},
+		{
+			"checksumSHA1": "OieGcyWgc9NzZb4TWXcufX560pc=",
+			"path": "github.com/smartystreets/assertions",
+			"revision": "287b4346dc4e71a038c346375a9d572453bc469b",
+			"revisionTime": "2016-02-05T03:39:31Z"
+		},
+		{
+			"checksumSHA1": "9iA8MD7dsY0eid8vy+1ixJHkR+M=",
+			"path": "github.com/smartystreets/assertions/internal/go-render/render",
+			"revision": "287b4346dc4e71a038c346375a9d572453bc469b",
+			"revisionTime": "2016-02-05T03:39:31Z"
+		},
+		{
+			"checksumSHA1": "QCsUvPHx/Ifqm+sJmocjSvePAIc=",
+			"path": "github.com/smartystreets/assertions/internal/oglematchers",
+			"revision": "287b4346dc4e71a038c346375a9d572453bc469b",
+			"revisionTime": "2016-02-05T03:39:31Z"
+		},
+		{
+			"checksumSHA1": "fQeXVv5U9dlo3ufH2vjk1GNf4Lo=",
+			"path": "github.com/smartystreets/goconvey/convey",
+			"revision": "bf58a9a1291224109919756b4dcc469c670cc7e4",
+			"revisionTime": "2016-02-05T03:35:52Z"
+		},
+		{
+			"checksumSHA1": "9LakndErFi5uCXtY1KWl0iRnT4c=",
+			"path": "github.com/smartystreets/goconvey/convey/gotest",
+			"revision": "bf58a9a1291224109919756b4dcc469c670cc7e4",
+			"revisionTime": "2016-02-05T03:35:52Z"
+		},
+		{
+			"checksumSHA1": "4NSMMeBraoAH+oebwoNzR9z25MM=",
+			"path": "github.com/smartystreets/goconvey/convey/reporting",
+			"revision": "bf58a9a1291224109919756b4dcc469c670cc7e4",
+			"revisionTime": "2016-02-05T03:35:52Z"
+		},
+		{
+			"checksumSHA1": "j+CXOooI5VyVEhKPTJkuL/GHPE0=",
+			"path": "github.com/urfave/cli",
+			"revision": "b6061c464d493dd94985211595687c862a0dd0bc",
+			"revisionTime": "2016-11-19T19:05:28Z"
+		},
+		{
+			"checksumSHA1": "dwOedwBJ1EIK9+S3t108Bx054Y8=",
+			"path": "golang.org/x/crypto/curve25519",
+			"revision": "d8e61c69ab46ca38328da2f4995abaf93b252290",
+			"revisionTime": "2016-12-13T22:25:08Z"
+		},
+		{
+			"checksumSHA1": "wGb//LjBPNxYHqk+dcLo7BjPXK8=",
+			"path": "golang.org/x/crypto/ed25519",
+			"revision": "d8e61c69ab46ca38328da2f4995abaf93b252290",
+			"revisionTime": "2016-12-13T22:25:08Z"
+		},
+		{
+			"checksumSHA1": "LXFcVx8I587SnWmKycSDEq9yvK8=",
+			"path": "golang.org/x/crypto/ed25519/internal/edwards25519",
+			"revision": "d8e61c69ab46ca38328da2f4995abaf93b252290",
+			"revisionTime": "2016-12-13T22:25:08Z"
+		},
+		{
+			"checksumSHA1": "MCeXr2RNeiG1XG6V+er1OR0qyeo=",
+			"path": "golang.org/x/crypto/md4",
+			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
+			"revisionTime": "2017-02-08T20:51:15Z"
+		},
+		{
+			"checksumSHA1": "1MGpGDQqnUoRpv7VEcQrXOBydXE=",
+			"path": "golang.org/x/crypto/pbkdf2",
+			"revision": "d8e61c69ab46ca38328da2f4995abaf93b252290",
+			"revisionTime": "2016-12-13T22:25:08Z"
+		},
+		{
+			"checksumSHA1": "fsrFs762jlaILyqqQImS1GfvIvw=",
+			"path": "golang.org/x/crypto/ssh",
+			"revision": "453249f01cfeb54c3d549ddb75ff152ca243f9d8",
+			"revisionTime": "2017-02-08T20:51:15Z"
+		},
+		{
+			"checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",
+			"path": "golang.org/x/net/context",
+			"revision": "45e771701b814666a7eb299e6c7a57d0b1799e91",
+			"revisionTime": "2016-12-15T19:42:18Z"
+		},
+		{
+			"checksumSHA1": "vqc3a+oTUGX8PmD0TS+qQ7gmN8I=",
+			"path": "golang.org/x/net/html",
+			"revision": "45e771701b814666a7eb299e6c7a57d0b1799e91",
+			"revisionTime": "2016-12-15T19:42:18Z"
+		},
+		{
+			"checksumSHA1": "00eQaGynDYrv3tL+C7l9xH0IDZg=",
+			"path": "golang.org/x/net/html/atom",
+			"revision": "45e771701b814666a7eb299e6c7a57d0b1799e91",
+			"revisionTime": "2016-12-15T19:42:18Z"
+		},
+		{
+			"checksumSHA1": "barUU39reQ7LdgYLA323hQ/UGy4=",
+			"path": "golang.org/x/net/html/charset",
+			"revision": "45e771701b814666a7eb299e6c7a57d0b1799e91",
+			"revisionTime": "2016-12-15T19:42:18Z"
+		},
+		{
+			"checksumSHA1": "KqecwXo3OO+p4N+E9RhlHvl9I+w=",
+			"path": "golang.org/x/sys/unix",
+			"revision": "b699b7032584f0953262cb2788a0ca19bb494703",
+			"revisionTime": "2016-11-10T11:58:56Z"
+		},
+		{
+			"checksumSHA1": "fpW2dhGFC6SrVzipJx7fjg2DIH8=",
+			"path": "golang.org/x/sys/windows",
+			"revision": "b699b7032584f0953262cb2788a0ca19bb494703",
+			"revisionTime": "2016-11-10T11:58:56Z"
+		},
+		{
+			"checksumSHA1": "IRqLaXM/VQRzkbXPuiqOxTb2W0Y=",
+			"path": "golang.org/x/sys/windows/svc",
+			"revision": "b699b7032584f0953262cb2788a0ca19bb494703",
+			"revisionTime": "2016-11-10T11:58:56Z"
+		},
+		{
+			"checksumSHA1": "Mr4ur60bgQJnQFfJY0dGtwWwMPE=",
+			"path": "golang.org/x/text/encoding",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "gJG/5S8KrCA1QGkIkpa5a/wnmy4=",
+			"path": "golang.org/x/text/encoding/charmap",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "mI8YM2LehMxYDcauq5loMZr1pP8=",
+			"path": "golang.org/x/text/encoding/htmlindex",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "zeHyHebIZl1tGuwGllIhjfci+wI=",
+			"path": "golang.org/x/text/encoding/internal",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "TF4hoIqHVEAvOq67rfnSLSkcZ1Y=",
+			"path": "golang.org/x/text/encoding/internal/identifier",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "HeZV82ktrmgyAaYLtNFS0qYgspI=",
+			"path": "golang.org/x/text/encoding/japanese",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "8y87WJz3OkDWtPCIXxJcYpo+OY8=",
+			"path": "golang.org/x/text/encoding/korean",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "WYfmebIyX5Zae8NUfu9PsQjQff0=",
+			"path": "golang.org/x/text/encoding/simplifiedchinese",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "KKqYmi6fxt3r3uo4lExss2yTMbs=",
+			"path": "golang.org/x/text/encoding/traditionalchinese",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "G9LfJI9gySazd+MyyC6QbTHx4to=",
+			"path": "golang.org/x/text/encoding/unicode",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "hyNCcTwMQnV6/MK8uUW9E5H0J0M=",
+			"path": "golang.org/x/text/internal/tag",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "Qk7dljcrEK1BJkAEZguxAbG9dSo=",
+			"path": "golang.org/x/text/internal/utf8internal",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "bsNFI/kfmF0p43jLKiMYRqw9Dfs=",
+			"path": "golang.org/x/text/language",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "IV4MN7KGBSocu/5NR3le3sxup4Y=",
+			"path": "golang.org/x/text/runes",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "ziMb9+ANGRJSSIuxYdRbA+cDRBQ=",
+			"path": "golang.org/x/text/transform",
+			"revision": "fa5033c827cad7080e8e7047a0091945b0e1f031",
+			"revisionTime": "2016-10-16T07:29:15Z"
+		},
+		{
+			"checksumSHA1": "6IzzHO9p32aHJhMYMwijccDUIVA=",
+			"path": "gopkg.in/alexcesaro/quotedprintable.v3",
+			"revision": "2caba252f4dc53eaf6b553000885530023f54623",
+			"revisionTime": "2015-07-16T17:19:45Z"
+		},
+		{
+			"checksumSHA1": "wSu8owMAP7GixsYoSZ4CmKUVhnU=",
+			"path": "gopkg.in/asn1-ber.v1",
+			"revision": "4e86f4367175e39f69d9358a5f17b4dda270378d",
+			"revisionTime": "2015-09-24T05:17:56Z"
+		},
+		{
+			"checksumSHA1": "ZJBrUSDBKgkXID1MVRkXSTlmOh4=",
+			"path": "gopkg.in/clog.v1",
+			"revision": "ff5a366d133e02b3d411dbe3854ebd912a434c7f",
+			"revisionTime": "2017-03-23T22:33:02Z"
+		},
+		{
+			"checksumSHA1": "LIu3jihd3edOyIsJJK3V6vx2UZg=",
+			"path": "gopkg.in/editorconfig/editorconfig-core-go.v1",
+			"revision": "a872f05c2e34b37b567401384d202aff11ba06d4",
+			"revisionTime": "2016-08-25T01:23:04Z"
+		},
+		{
+			"checksumSHA1": "iq5WdjScmTU+LfNoerLuwcnXpdM=",
+			"path": "gopkg.in/gomail.v2",
+			"revision": "81ebce5c23dfd25c6c67194b37d3dd3f338c98b1",
+			"revisionTime": "2016-04-11T21:29:32Z"
+		},
+		{
+			"checksumSHA1": "/nX/at2Sz9tc1TJ/ay6J9or5Uzc=",
+			"path": "gopkg.in/ini.v1",
+			"revision": "ee900ca565931451fe4e4409bcbd4316331cec1c",
+			"revisionTime": "2017-02-09T04:24:15Z"
+		},
+		{
+			"checksumSHA1": "7jPSjzw3mckHVQ2SjY4NvtIJR4g=",
+			"path": "gopkg.in/ldap.v2",
+			"revision": "d0a5ced67b4dc310b9158d63a2c6f9c5ec13f105",
+			"revisionTime": "2016-08-08T14:54:09Z"
+		},
+		{
+			"checksumSHA1": "qM9ubEa57g4oNa6JLFQ+e1TCMno=",
+			"path": "gopkg.in/macaron.v1",
+			"revision": "a325110f8b392bce3e5cdeb8c44bf98078ada3be",
+			"revisionTime": "2017-02-19T20:49:11Z"
+		},
+		{
+			"checksumSHA1": "6QPjE+qflEBHg+JPJd9e4iQuRAk=",
+			"path": "gopkg.in/redis.v2",
+			"revision": "e6179049628164864e6e84e973cfb56335748dea",
+			"revisionTime": "2014-12-09T11:07:59Z"
+		}
+	],
+	"rootPath": "github.com/gogits/gogs"
+}