merge in studio-1.4-release history after reset to studio-master-dev
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..d2f212e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,10 @@
+# Treat all files in this repo as binary, with no git magic updating
+# line endings. Windows users contributing to Go will need to use a
+# modern version of git and editors capable of LF line endings.
+#
+# We'll prevent accidental CRLF line endings from entering the repo
+# via the git-review gofmt checks.
+#
+# See golang.org/issue/9281
+
+* -text
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5a9d62e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+# Add no patterns to .gitignore except for files generated by the build.
+last-change
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..15167cd
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+# This source code refers to The Go Authors for copyright purposes.
+# The master list of authors is in the main Go distribution,
+# visible at http://tip.golang.org/AUTHORS.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..88dff59
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,31 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
new file mode 100644
index 0000000..1c4577e
--- /dev/null
+++ b/CONTRIBUTORS
@@ -0,0 +1,3 @@
+# This source code was written by the Go contributors.
+# The master list of contributors is in the main Go distribution,
+# visible at http://tip.golang.org/CONTRIBUTORS.
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..6a66aea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2009 The Go Authors. 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 Google Inc. 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
+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.
diff --git a/PATENTS b/PATENTS
new file mode 100644
index 0000000..7330990
--- /dev/null
+++ b/PATENTS
@@ -0,0 +1,22 @@
+Additional IP Rights Grant (Patents)
+
+"This implementation" means the copyrightable works distributed by
+Google as part of the Go project.
+
+Google hereby grants to You a perpetual, worldwide, non-exclusive,
+no-charge, royalty-free, irrevocable (except as stated in this section)
+patent license to make, have made, use, offer to sell, sell, import,
+transfer and otherwise run, modify and propagate the contents of this
+implementation of Go, where such license applies only to those patent
+claims, both currently owned or controlled by Google and acquired in
+the future, licensable by Google that are necessarily infringed by this
+implementation of Go.  This grant does not include claims that would be
+infringed only as a consequence of further modification of this
+implementation.  If you or your agent or exclusive licensee institute or
+order or agree to the institution of patent litigation against any
+entity (including a cross-claim or counterclaim in a lawsuit) alleging
+that this implementation of Go or any code incorporated within this
+implementation of Go constitutes direct or contributory patent
+infringement, or inducement of patent infringement, then any patent
+rights granted to you under this License for this implementation of Go
+shall terminate as of the date such litigation is filed.
diff --git a/README b/README
new file mode 100644
index 0000000..916ae2e
--- /dev/null
+++ b/README
@@ -0,0 +1,10 @@
+This subrepository holds the source for various packages and tools that support
+the Go programming language.
+
+Some of the tools, godoc and vet for example, are included in binary Go distributions.
+Others, including the Go oracle and the test coverage tool, can be fetched with "go get".
+
+Packages include a type-checker for Go and an implementation of the
+Static Single Assignment form (SSA) representation for Go programs.
+
+To submit changes to this repository, see http://golang.org/doc/contribute.html.
diff --git a/benchmark/parse/parse.go b/benchmark/parse/parse.go
new file mode 100644
index 0000000..b37e6f0
--- /dev/null
+++ b/benchmark/parse/parse.go
@@ -0,0 +1,131 @@
+// Copyright 2014 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 parse provides support for parsing benchmark results as
+// generated by 'go test -bench'.
+package parse // import "golang.org/x/tools/benchmark/parse"
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+// Flags used by Benchmark.Measured to indicate
+// which measurements a Benchmark contains.
+const (
+	NsPerOp = 1 << iota
+	MBPerS
+	AllocedBytesPerOp
+	AllocsPerOp
+)
+
+// Benchmark is one run of a single benchmark.
+type Benchmark struct {
+	Name              string  // benchmark name
+	N                 int     // number of iterations
+	NsPerOp           float64 // nanoseconds per iteration
+	AllocedBytesPerOp uint64  // bytes allocated per iteration
+	AllocsPerOp       uint64  // allocs per iteration
+	MBPerS            float64 // MB processed per second
+	Measured          int     // which measurements were recorded
+	Ord               int     // ordinal position within a benchmark run
+}
+
+// ParseLine extracts a Benchmark from a single line of testing.B
+// output.
+func ParseLine(line string) (*Benchmark, error) {
+	fields := strings.Fields(line)
+
+	// Two required, positional fields: Name and iterations.
+	if len(fields) < 2 {
+		return nil, fmt.Errorf("two fields required, have %d", len(fields))
+	}
+	if !strings.HasPrefix(fields[0], "Benchmark") {
+		return nil, fmt.Errorf(`first field does not start with "Benchmark"`)
+	}
+	n, err := strconv.Atoi(fields[1])
+	if err != nil {
+		return nil, err
+	}
+	b := &Benchmark{Name: fields[0], N: n}
+
+	// Parse any remaining pairs of fields; we've parsed one pair already.
+	for i := 1; i < len(fields)/2; i++ {
+		b.parseMeasurement(fields[i*2], fields[i*2+1])
+	}
+	return b, nil
+}
+
+func (b *Benchmark) parseMeasurement(quant string, unit string) {
+	switch unit {
+	case "ns/op":
+		if f, err := strconv.ParseFloat(quant, 64); err == nil {
+			b.NsPerOp = f
+			b.Measured |= NsPerOp
+		}
+	case "MB/s":
+		if f, err := strconv.ParseFloat(quant, 64); err == nil {
+			b.MBPerS = f
+			b.Measured |= MBPerS
+		}
+	case "B/op":
+		if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
+			b.AllocedBytesPerOp = i
+			b.Measured |= AllocedBytesPerOp
+		}
+	case "allocs/op":
+		if i, err := strconv.ParseUint(quant, 10, 64); err == nil {
+			b.AllocsPerOp = i
+			b.Measured |= AllocsPerOp
+		}
+	}
+}
+
+func (b *Benchmark) String() string {
+	buf := new(bytes.Buffer)
+	fmt.Fprintf(buf, "%s %d", b.Name, b.N)
+	if (b.Measured & NsPerOp) != 0 {
+		fmt.Fprintf(buf, " %.2f ns/op", b.NsPerOp)
+	}
+	if (b.Measured & MBPerS) != 0 {
+		fmt.Fprintf(buf, " %.2f MB/s", b.MBPerS)
+	}
+	if (b.Measured & AllocedBytesPerOp) != 0 {
+		fmt.Fprintf(buf, " %d B/op", b.AllocedBytesPerOp)
+	}
+	if (b.Measured & AllocsPerOp) != 0 {
+		fmt.Fprintf(buf, " %d allocs/op", b.AllocsPerOp)
+	}
+	return buf.String()
+}
+
+// Set is a collection of benchmarks from one
+// testing.B run, keyed by name to facilitate comparison.
+type Set map[string][]*Benchmark
+
+// ParseSet extracts a Set from testing.B output.
+// ParseSet preserves the order of benchmarks that have identical
+// names.
+func ParseSet(r io.Reader) (Set, error) {
+	bb := make(Set)
+	scan := bufio.NewScanner(r)
+	ord := 0
+	for scan.Scan() {
+		if b, err := ParseLine(scan.Text()); err == nil {
+			b.Ord = ord
+			ord++
+			bb[b.Name] = append(bb[b.Name], b)
+		}
+	}
+
+	if err := scan.Err(); err != nil {
+		return nil, err
+	}
+
+	return bb, nil
+}
diff --git a/benchmark/parse/parse_test.go b/benchmark/parse/parse_test.go
new file mode 100644
index 0000000..06db848
--- /dev/null
+++ b/benchmark/parse/parse_test.go
@@ -0,0 +1,154 @@
+// Copyright 2014 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 parse
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestParseLine(t *testing.T) {
+	cases := []struct {
+		line string
+		want *Benchmark
+		err  bool // expect an error
+	}{
+		{
+			line: "BenchmarkEncrypt	100000000	        19.6 ns/op",
+			want: &Benchmark{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6,
+				Measured: NsPerOp,
+			},
+		},
+		{
+			line: "BenchmarkEncrypt	100000000	        19.6 ns/op	 817.77 MB/s",
+			want: &Benchmark{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6, MBPerS: 817.77,
+				Measured: NsPerOp | MBPerS,
+			},
+		},
+		{
+			line: "BenchmarkEncrypt	100000000	        19.6 ns/op	 817.77",
+			want: &Benchmark{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6,
+				Measured: NsPerOp,
+			},
+		},
+		{
+			line: "BenchmarkEncrypt	100000000	        19.6 ns/op	 817.77 MB/s	       5 allocs/op",
+			want: &Benchmark{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6, MBPerS: 817.77, AllocsPerOp: 5,
+				Measured: NsPerOp | MBPerS | AllocsPerOp,
+			},
+		},
+		{
+			line: "BenchmarkEncrypt	100000000	        19.6 ns/op	 817.77 MB/s	       3 B/op	       5 allocs/op",
+			want: &Benchmark{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6, MBPerS: 817.77, AllocedBytesPerOp: 3, AllocsPerOp: 5,
+				Measured: NsPerOp | MBPerS | AllocedBytesPerOp | AllocsPerOp,
+			},
+		},
+		// error handling cases
+		{
+			line: "BenchPress	100	        19.6 ns/op", // non-benchmark
+			err: true,
+		},
+		{
+			line: "BenchmarkEncrypt	lots	        19.6 ns/op", // non-int iterations
+			err: true,
+		},
+		{
+			line: "BenchmarkBridge	100000000	        19.6 smoots", // unknown unit
+			want: &Benchmark{
+				Name: "BenchmarkBridge",
+				N:    100000000,
+			},
+		},
+		{
+			line: "PASS",
+			err:  true,
+		},
+	}
+
+	for _, tt := range cases {
+		have, err := ParseLine(tt.line)
+		if tt.err && err == nil {
+			t.Errorf("parsing line %q should have failed", tt.line)
+			continue
+		}
+		if !reflect.DeepEqual(have, tt.want) {
+			t.Errorf("parsed line %q incorrectly, want %v have %v", tt.line, tt.want, have)
+		}
+	}
+}
+
+func TestParseSet(t *testing.T) {
+	// Test two things:
+	// 1. The noise that can accompany testing.B output gets ignored.
+	// 2. Benchmarks with the same name have their order preserved.
+	in := `
+		?   	crypto	[no test files]
+		PASS
+				pem_decrypt_test.go:17: test 4. %!s(x509.PEMCipher=5)
+			... [output truncated]
+
+		BenchmarkEncrypt	100000000	        19.6 ns/op
+		BenchmarkEncrypt	 5000000	       517 ns/op
+		=== RUN TestChunk
+		--- PASS: TestChunk (0.00 seconds)
+		--- SKIP: TestLinuxSendfile (0.00 seconds)
+			fs_test.go:716: skipping; linux-only test
+		BenchmarkReadRequestApachebench	 1000000	      2960 ns/op	  27.70 MB/s	     839 B/op	       9 allocs/op
+		BenchmarkClientServerParallel64	   50000	     59192 ns/op	    7028 B/op	      60 allocs/op
+		ok  	net/http	95.783s
+	`
+
+	want := Set{
+		"BenchmarkReadRequestApachebench": []*Benchmark{
+			{
+				Name: "BenchmarkReadRequestApachebench",
+				N:    1000000, NsPerOp: 2960, MBPerS: 27.70, AllocedBytesPerOp: 839, AllocsPerOp: 9,
+				Measured: NsPerOp | MBPerS | AllocedBytesPerOp | AllocsPerOp,
+				Ord:      2,
+			},
+		},
+		"BenchmarkClientServerParallel64": []*Benchmark{
+			{
+				Name: "BenchmarkClientServerParallel64",
+				N:    50000, NsPerOp: 59192, AllocedBytesPerOp: 7028, AllocsPerOp: 60,
+				Measured: NsPerOp | AllocedBytesPerOp | AllocsPerOp,
+				Ord:      3,
+			},
+		},
+		"BenchmarkEncrypt": []*Benchmark{
+			{
+				Name: "BenchmarkEncrypt",
+				N:    100000000, NsPerOp: 19.6,
+				Measured: NsPerOp,
+				Ord:      0,
+			},
+			{
+				Name: "BenchmarkEncrypt",
+				N:    5000000, NsPerOp: 517,
+				Measured: NsPerOp,
+				Ord:      1,
+			},
+		},
+	}
+
+	have, err := ParseSet(strings.NewReader(in))
+	if err != nil {
+		t.Fatalf("unexpected err during ParseSet: %v", err)
+	}
+	if !reflect.DeepEqual(want, have) {
+		t.Errorf("parsed bench set incorrectly, want %v have %v", want, have)
+	}
+}
diff --git a/blog/atom/atom.go b/blog/atom/atom.go
new file mode 100644
index 0000000..f12c31d
--- /dev/null
+++ b/blog/atom/atom.go
@@ -0,0 +1,57 @@
+// Copyright 2009 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.
+
+// Adapted from encoding/xml/read_test.go.
+
+// Package atom defines XML data structures for an Atom feed.
+package atom // import "golang.org/x/tools/blog/atom"
+
+import (
+	"encoding/xml"
+	"time"
+)
+
+type Feed struct {
+	XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"`
+	Title   string   `xml:"title"`
+	ID      string   `xml:"id"`
+	Link    []Link   `xml:"link"`
+	Updated TimeStr  `xml:"updated"`
+	Author  *Person  `xml:"author"`
+	Entry   []*Entry `xml:"entry"`
+}
+
+type Entry struct {
+	Title     string  `xml:"title"`
+	ID        string  `xml:"id"`
+	Link      []Link  `xml:"link"`
+	Published TimeStr `xml:"published"`
+	Updated   TimeStr `xml:"updated"`
+	Author    *Person `xml:"author"`
+	Summary   *Text   `xml:"summary"`
+	Content   *Text   `xml:"content"`
+}
+
+type Link struct {
+	Rel  string `xml:"rel,attr"`
+	Href string `xml:"href,attr"`
+}
+
+type Person struct {
+	Name     string `xml:"name"`
+	URI      string `xml:"uri,omitempty"`
+	Email    string `xml:"email,omitempty"`
+	InnerXML string `xml:",innerxml"`
+}
+
+type Text struct {
+	Type string `xml:"type,attr"`
+	Body string `xml:",chardata"`
+}
+
+type TimeStr string
+
+func Time(t time.Time) TimeStr {
+	return TimeStr(t.Format("2006-01-02T15:04:05-07:00"))
+}
diff --git a/blog/blog.go b/blog/blog.go
new file mode 100644
index 0000000..23c8dc6
--- /dev/null
+++ b/blog/blog.go
@@ -0,0 +1,424 @@
+// Copyright 2013 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 blog implements a web server for articles written in present format.
+package blog // import "golang.org/x/tools/blog"
+
+import (
+	"bytes"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"html/template"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"regexp"
+	"sort"
+	"strings"
+	"time"
+
+	"golang.org/x/tools/blog/atom"
+	"golang.org/x/tools/present"
+)
+
+var validJSONPFunc = regexp.MustCompile(`(?i)^[a-z_][a-z0-9_.]*$`)
+
+// Config specifies Server configuration values.
+type Config struct {
+	ContentPath  string // Relative or absolute location of article files and related content.
+	TemplatePath string // Relative or absolute location of template files.
+
+	BaseURL  string // Absolute base URL (for permalinks; no trailing slash).
+	BasePath string // Base URL path relative to server root (no trailing slash).
+	GodocURL string // The base URL of godoc (for menu bar; no trailing slash).
+	Hostname string // Server host name, used for rendering ATOM feeds.
+
+	HomeArticles int    // Articles to display on the home page.
+	FeedArticles int    // Articles to include in Atom and JSON feeds.
+	FeedTitle    string // The title of the Atom XML feed
+
+	PlayEnabled bool
+}
+
+// Doc represents an article adorned with presentation data.
+type Doc struct {
+	*present.Doc
+	Permalink string        // Canonical URL for this document.
+	Path      string        // Path relative to server root (including base).
+	HTML      template.HTML // rendered article
+
+	Related      []*Doc
+	Newer, Older *Doc
+}
+
+// Server implements an http.Handler that serves blog articles.
+type Server struct {
+	cfg      Config
+	docs     []*Doc
+	tags     []string
+	docPaths map[string]*Doc // key is path without BasePath.
+	docTags  map[string][]*Doc
+	template struct {
+		home, index, article, doc *template.Template
+	}
+	atomFeed []byte // pre-rendered Atom feed
+	jsonFeed []byte // pre-rendered JSON feed
+	content  http.Handler
+}
+
+// NewServer constructs a new Server using the specified config.
+func NewServer(cfg Config) (*Server, error) {
+	present.PlayEnabled = cfg.PlayEnabled
+
+	root := filepath.Join(cfg.TemplatePath, "root.tmpl")
+	parse := func(name string) (*template.Template, error) {
+		t := template.New("").Funcs(funcMap)
+		return t.ParseFiles(root, filepath.Join(cfg.TemplatePath, name))
+	}
+
+	s := &Server{cfg: cfg}
+
+	// Parse templates.
+	var err error
+	s.template.home, err = parse("home.tmpl")
+	if err != nil {
+		return nil, err
+	}
+	s.template.index, err = parse("index.tmpl")
+	if err != nil {
+		return nil, err
+	}
+	s.template.article, err = parse("article.tmpl")
+	if err != nil {
+		return nil, err
+	}
+	p := present.Template().Funcs(funcMap)
+	s.template.doc, err = p.ParseFiles(filepath.Join(cfg.TemplatePath, "doc.tmpl"))
+	if err != nil {
+		return nil, err
+	}
+
+	// Load content.
+	err = s.loadDocs(filepath.Clean(cfg.ContentPath))
+	if err != nil {
+		return nil, err
+	}
+
+	err = s.renderAtomFeed()
+	if err != nil {
+		return nil, err
+	}
+
+	err = s.renderJSONFeed()
+	if err != nil {
+		return nil, err
+	}
+
+	// Set up content file server.
+	s.content = http.StripPrefix(s.cfg.BasePath, http.FileServer(http.Dir(cfg.ContentPath)))
+
+	return s, nil
+}
+
+var funcMap = template.FuncMap{
+	"sectioned": sectioned,
+	"authors":   authors,
+}
+
+// sectioned returns true if the provided Doc contains more than one section.
+// This is used to control whether to display the table of contents and headings.
+func sectioned(d *present.Doc) bool {
+	return len(d.Sections) > 1
+}
+
+// authors returns a comma-separated list of author names.
+func authors(authors []present.Author) string {
+	var b bytes.Buffer
+	last := len(authors) - 1
+	for i, a := range authors {
+		if i > 0 {
+			if i == last {
+				b.WriteString(" and ")
+			} else {
+				b.WriteString(", ")
+			}
+		}
+		b.WriteString(authorName(a))
+	}
+	return b.String()
+}
+
+// authorName returns the first line of the Author text: the author's name.
+func authorName(a present.Author) string {
+	el := a.TextElem()
+	if len(el) == 0 {
+		return ""
+	}
+	text, ok := el[0].(present.Text)
+	if !ok || len(text.Lines) == 0 {
+		return ""
+	}
+	return text.Lines[0]
+}
+
+// loadDocs reads all content from the provided file system root, renders all
+// the articles it finds, adds them to the Server's docs field, computes the
+// denormalized docPaths, docTags, and tags fields, and populates the various
+// helper fields (Next, Previous, Related) for each Doc.
+func (s *Server) loadDocs(root string) error {
+	// Read content into docs field.
+	const ext = ".article"
+	fn := func(p string, info os.FileInfo, err error) error {
+		if filepath.Ext(p) != ext {
+			return nil
+		}
+		f, err := os.Open(p)
+		if err != nil {
+			return err
+		}
+		defer f.Close()
+		d, err := present.Parse(f, p, 0)
+		if err != nil {
+			return err
+		}
+		html := new(bytes.Buffer)
+		err = d.Render(html, s.template.doc)
+		if err != nil {
+			return err
+		}
+		p = p[len(root) : len(p)-len(ext)] // trim root and extension
+		p = filepath.ToSlash(p)
+		s.docs = append(s.docs, &Doc{
+			Doc:       d,
+			Path:      s.cfg.BasePath + p,
+			Permalink: s.cfg.BaseURL + p,
+			HTML:      template.HTML(html.String()),
+		})
+		return nil
+	}
+	err := filepath.Walk(root, fn)
+	if err != nil {
+		return err
+	}
+	sort.Sort(docsByTime(s.docs))
+
+	// Pull out doc paths and tags and put in reverse-associating maps.
+	s.docPaths = make(map[string]*Doc)
+	s.docTags = make(map[string][]*Doc)
+	for _, d := range s.docs {
+		s.docPaths[strings.TrimPrefix(d.Path, s.cfg.BasePath)] = d
+		for _, t := range d.Tags {
+			s.docTags[t] = append(s.docTags[t], d)
+		}
+	}
+
+	// Pull out unique sorted list of tags.
+	for t := range s.docTags {
+		s.tags = append(s.tags, t)
+	}
+	sort.Strings(s.tags)
+
+	// Set up presentation-related fields, Newer, Older, and Related.
+	for _, doc := range s.docs {
+		// Newer, Older: docs adjacent to doc
+		for i := range s.docs {
+			if s.docs[i] != doc {
+				continue
+			}
+			if i > 0 {
+				doc.Newer = s.docs[i-1]
+			}
+			if i+1 < len(s.docs) {
+				doc.Older = s.docs[i+1]
+			}
+			break
+		}
+
+		// Related: all docs that share tags with doc.
+		related := make(map[*Doc]bool)
+		for _, t := range doc.Tags {
+			for _, d := range s.docTags[t] {
+				if d != doc {
+					related[d] = true
+				}
+			}
+		}
+		for d := range related {
+			doc.Related = append(doc.Related, d)
+		}
+		sort.Sort(docsByTime(doc.Related))
+	}
+
+	return nil
+}
+
+// renderAtomFeed generates an XML Atom feed and stores it in the Server's
+// atomFeed field.
+func (s *Server) renderAtomFeed() error {
+	var updated time.Time
+	if len(s.docs) > 0 {
+		updated = s.docs[0].Time
+	}
+	feed := atom.Feed{
+		Title:   s.cfg.FeedTitle,
+		ID:      "tag:" + s.cfg.Hostname + ",2013:" + s.cfg.Hostname,
+		Updated: atom.Time(updated),
+		Link: []atom.Link{{
+			Rel:  "self",
+			Href: s.cfg.BaseURL + "/feed.atom",
+		}},
+	}
+	for i, doc := range s.docs {
+		if i >= s.cfg.FeedArticles {
+			break
+		}
+		e := &atom.Entry{
+			Title: doc.Title,
+			ID:    feed.ID + doc.Path,
+			Link: []atom.Link{{
+				Rel:  "alternate",
+				Href: doc.Permalink,
+			}},
+			Published: atom.Time(doc.Time),
+			Updated:   atom.Time(doc.Time),
+			Summary: &atom.Text{
+				Type: "html",
+				Body: summary(doc),
+			},
+			Content: &atom.Text{
+				Type: "html",
+				Body: string(doc.HTML),
+			},
+			Author: &atom.Person{
+				Name: authors(doc.Authors),
+			},
+		}
+		feed.Entry = append(feed.Entry, e)
+	}
+	data, err := xml.Marshal(&feed)
+	if err != nil {
+		return err
+	}
+	s.atomFeed = data
+	return nil
+}
+
+type jsonItem struct {
+	Title   string
+	Link    string
+	Time    time.Time
+	Summary string
+	Content string
+	Author  string
+}
+
+// renderJSONFeed generates a JSON feed and stores it in the Server's jsonFeed
+// field.
+func (s *Server) renderJSONFeed() error {
+	var feed []jsonItem
+	for i, doc := range s.docs {
+		if i >= s.cfg.FeedArticles {
+			break
+		}
+		item := jsonItem{
+			Title:   doc.Title,
+			Link:    doc.Permalink,
+			Time:    doc.Time,
+			Summary: summary(doc),
+			Content: string(doc.HTML),
+			Author:  authors(doc.Authors),
+		}
+		feed = append(feed, item)
+	}
+	data, err := json.Marshal(feed)
+	if err != nil {
+		return err
+	}
+	s.jsonFeed = data
+	return nil
+}
+
+// summary returns the first paragraph of text from the provided Doc.
+func summary(d *Doc) string {
+	if len(d.Sections) == 0 {
+		return ""
+	}
+	for _, elem := range d.Sections[0].Elem {
+		text, ok := elem.(present.Text)
+		if !ok || text.Pre {
+			// skip everything but non-text elements
+			continue
+		}
+		var buf bytes.Buffer
+		for _, s := range text.Lines {
+			buf.WriteString(string(present.Style(s)))
+			buf.WriteByte('\n')
+		}
+		return buf.String()
+	}
+	return ""
+}
+
+// rootData encapsulates data destined for the root template.
+type rootData struct {
+	Doc      *Doc
+	BasePath string
+	GodocURL string
+	Data     interface{}
+}
+
+// ServeHTTP serves the front, index, and article pages
+// as well as the ATOM and JSON feeds.
+func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	var (
+		d = rootData{BasePath: s.cfg.BasePath, GodocURL: s.cfg.GodocURL}
+		t *template.Template
+	)
+	switch p := strings.TrimPrefix(r.URL.Path, s.cfg.BasePath); p {
+	case "/":
+		d.Data = s.docs
+		if len(s.docs) > s.cfg.HomeArticles {
+			d.Data = s.docs[:s.cfg.HomeArticles]
+		}
+		t = s.template.home
+	case "/index":
+		d.Data = s.docs
+		t = s.template.index
+	case "/feed.atom", "/feeds/posts/default":
+		w.Header().Set("Content-type", "application/atom+xml; charset=utf-8")
+		w.Write(s.atomFeed)
+		return
+	case "/.json":
+		if p := r.FormValue("jsonp"); validJSONPFunc.MatchString(p) {
+			w.Header().Set("Content-type", "application/javascript; charset=utf-8")
+			fmt.Fprintf(w, "%v(%s)", p, s.jsonFeed)
+			return
+		}
+		w.Header().Set("Content-type", "application/json; charset=utf-8")
+		w.Write(s.jsonFeed)
+		return
+	default:
+		doc, ok := s.docPaths[p]
+		if !ok {
+			// Not a doc; try to just serve static content.
+			s.content.ServeHTTP(w, r)
+			return
+		}
+		d.Doc = doc
+		t = s.template.article
+	}
+	err := t.ExecuteTemplate(w, "root", d)
+	if err != nil {
+		log.Println(err)
+	}
+}
+
+// docsByTime implements sort.Interface, sorting Docs by their Time field.
+type docsByTime []*Doc
+
+func (s docsByTime) Len() int           { return len(s) }
+func (s docsByTime) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s docsByTime) Less(i, j int) bool { return s[i].Time.After(s[j].Time) }
diff --git a/cmd/benchcmp/benchcmp.go b/cmd/benchcmp/benchcmp.go
new file mode 100644
index 0000000..32f3a1c
--- /dev/null
+++ b/cmd/benchcmp/benchcmp.go
@@ -0,0 +1,184 @@
+// Copyright 2014 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 main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"sort"
+	"strconv"
+	"text/tabwriter"
+
+	"golang.org/x/tools/benchmark/parse"
+)
+
+var (
+	changedOnly = flag.Bool("changed", false, "show only benchmarks that have changed")
+	magSort     = flag.Bool("mag", false, "sort benchmarks by magnitude of change")
+	best        = flag.Bool("best", false, "compare best times from old and new")
+)
+
+const usageFooter = `
+Each input file should be from:
+	go test -run=NONE -bench=. > [old,new].txt
+
+Benchcmp compares old and new for each benchmark.
+
+If -test.benchmem=true is added to the "go test" command
+benchcmp will also compare memory allocations.
+`
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, "usage: %s old.txt new.txt\n\n", os.Args[0])
+		flag.PrintDefaults()
+		fmt.Fprint(os.Stderr, usageFooter)
+		os.Exit(2)
+	}
+	flag.Parse()
+	if flag.NArg() != 2 {
+		flag.Usage()
+	}
+
+	before := parseFile(flag.Arg(0))
+	after := parseFile(flag.Arg(1))
+
+	cmps, warnings := Correlate(before, after)
+
+	for _, warn := range warnings {
+		fmt.Fprintln(os.Stderr, warn)
+	}
+
+	if len(cmps) == 0 {
+		fatal("benchcmp: no repeated benchmarks")
+	}
+
+	w := new(tabwriter.Writer)
+	w.Init(os.Stdout, 0, 0, 5, ' ', 0)
+	defer w.Flush()
+
+	var header bool // Has the header has been displayed yet for a given block?
+
+	if *magSort {
+		sort.Sort(ByDeltaNsPerOp(cmps))
+	} else {
+		sort.Sort(ByParseOrder(cmps))
+	}
+	for _, cmp := range cmps {
+		if !cmp.Measured(parse.NsPerOp) {
+			continue
+		}
+		if delta := cmp.DeltaNsPerOp(); !*changedOnly || delta.Changed() {
+			if !header {
+				fmt.Fprint(w, "benchmark\told ns/op\tnew ns/op\tdelta\n")
+				header = true
+			}
+			fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", cmp.Name(), formatNs(cmp.Before.NsPerOp), formatNs(cmp.After.NsPerOp), delta.Percent())
+		}
+	}
+
+	header = false
+	if *magSort {
+		sort.Sort(ByDeltaMBPerS(cmps))
+	}
+	for _, cmp := range cmps {
+		if !cmp.Measured(parse.MBPerS) {
+			continue
+		}
+		if delta := cmp.DeltaMBPerS(); !*changedOnly || delta.Changed() {
+			if !header {
+				fmt.Fprint(w, "\nbenchmark\told MB/s\tnew MB/s\tspeedup\n")
+				header = true
+			}
+			fmt.Fprintf(w, "%s\t%.2f\t%.2f\t%s\n", cmp.Name(), cmp.Before.MBPerS, cmp.After.MBPerS, delta.Multiple())
+		}
+	}
+
+	header = false
+	if *magSort {
+		sort.Sort(ByDeltaAllocsPerOp(cmps))
+	}
+	for _, cmp := range cmps {
+		if !cmp.Measured(parse.AllocsPerOp) {
+			continue
+		}
+		if delta := cmp.DeltaAllocsPerOp(); !*changedOnly || delta.Changed() {
+			if !header {
+				fmt.Fprint(w, "\nbenchmark\told allocs\tnew allocs\tdelta\n")
+				header = true
+			}
+			fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocsPerOp, cmp.After.AllocsPerOp, delta.Percent())
+		}
+	}
+
+	header = false
+	if *magSort {
+		sort.Sort(ByDeltaAllocedBytesPerOp(cmps))
+	}
+	for _, cmp := range cmps {
+		if !cmp.Measured(parse.AllocedBytesPerOp) {
+			continue
+		}
+		if delta := cmp.DeltaAllocedBytesPerOp(); !*changedOnly || delta.Changed() {
+			if !header {
+				fmt.Fprint(w, "\nbenchmark\told bytes\tnew bytes\tdelta\n")
+				header = true
+			}
+			fmt.Fprintf(w, "%s\t%d\t%d\t%s\n", cmp.Name(), cmp.Before.AllocedBytesPerOp, cmp.After.AllocedBytesPerOp, cmp.DeltaAllocedBytesPerOp().Percent())
+		}
+	}
+}
+
+func fatal(msg interface{}) {
+	fmt.Fprintln(os.Stderr, msg)
+	os.Exit(1)
+}
+
+func parseFile(path string) parse.Set {
+	f, err := os.Open(path)
+	if err != nil {
+		fatal(err)
+	}
+	defer f.Close()
+	bb, err := parse.ParseSet(f)
+	if err != nil {
+		fatal(err)
+	}
+	if *best {
+		selectBest(bb)
+	}
+	return bb
+}
+
+func selectBest(bs parse.Set) {
+	for name, bb := range bs {
+		if len(bb) < 2 {
+			continue
+		}
+		ord := bb[0].Ord
+		best := bb[0]
+		for _, b := range bb {
+			if b.NsPerOp < best.NsPerOp {
+				b.Ord = ord
+				best = b
+			}
+		}
+		bs[name] = []*parse.Benchmark{best}
+	}
+}
+
+// formatNs formats ns measurements to expose a useful amount of
+// precision. It mirrors the ns precision logic of testing.B.
+func formatNs(ns float64) string {
+	prec := 0
+	switch {
+	case ns < 10:
+		prec = 2
+	case ns < 100:
+		prec = 1
+	}
+	return strconv.FormatFloat(ns, 'f', prec, 64)
+}
diff --git a/cmd/benchcmp/benchcmp_test.go b/cmd/benchcmp/benchcmp_test.go
new file mode 100644
index 0000000..2226079
--- /dev/null
+++ b/cmd/benchcmp/benchcmp_test.go
@@ -0,0 +1,59 @@
+package main
+
+import (
+	"reflect"
+	"testing"
+
+	"golang.org/x/tools/benchmark/parse"
+)
+
+func TestSelectBest(t *testing.T) {
+	have := parse.Set{
+		"Benchmark1": []*parse.Benchmark{
+			{
+				Name: "Benchmark1",
+				N:    10, NsPerOp: 100, Measured: parse.NsPerOp,
+				Ord: 0,
+			},
+			{
+				Name: "Benchmark1",
+				N:    10, NsPerOp: 50, Measured: parse.NsPerOp,
+				Ord: 3,
+			},
+		},
+		"Benchmark2": []*parse.Benchmark{
+			{
+				Name: "Benchmark2",
+				N:    10, NsPerOp: 60, Measured: parse.NsPerOp,
+				Ord: 1,
+			},
+			{
+				Name: "Benchmark2",
+				N:    10, NsPerOp: 500, Measured: parse.NsPerOp,
+				Ord: 2,
+			},
+		},
+	}
+
+	want := parse.Set{
+		"Benchmark1": []*parse.Benchmark{
+			{
+				Name: "Benchmark1",
+				N:    10, NsPerOp: 50, Measured: parse.NsPerOp,
+				Ord: 0,
+			},
+		},
+		"Benchmark2": []*parse.Benchmark{
+			{
+				Name: "Benchmark2",
+				N:    10, NsPerOp: 60, Measured: parse.NsPerOp,
+				Ord: 1,
+			},
+		},
+	}
+
+	selectBest(have)
+	if !reflect.DeepEqual(want, have) {
+		t.Errorf("filtered bench set incorrectly, want %v have %v", want, have)
+	}
+}
diff --git a/cmd/benchcmp/compare.go b/cmd/benchcmp/compare.go
new file mode 100644
index 0000000..c3f5e89
--- /dev/null
+++ b/cmd/benchcmp/compare.go
@@ -0,0 +1,156 @@
+// Copyright 2014 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 main
+
+import (
+	"fmt"
+	"math"
+
+	"golang.org/x/tools/benchmark/parse"
+)
+
+// BenchCmp is a pair of benchmarks.
+type BenchCmp struct {
+	Before *parse.Benchmark
+	After  *parse.Benchmark
+}
+
+// Correlate correlates benchmarks from two BenchSets.
+func Correlate(before, after parse.Set) (cmps []BenchCmp, warnings []string) {
+	cmps = make([]BenchCmp, 0, len(after))
+	for name, beforebb := range before {
+		afterbb := after[name]
+		if len(beforebb) != len(afterbb) {
+			warnings = append(warnings, fmt.Sprintf("ignoring %s: before has %d instances, after has %d", name, len(beforebb), len(afterbb)))
+			continue
+		}
+		for i, beforeb := range beforebb {
+			afterb := afterbb[i]
+			cmps = append(cmps, BenchCmp{beforeb, afterb})
+		}
+	}
+	return
+}
+
+func (c BenchCmp) Name() string           { return c.Before.Name }
+func (c BenchCmp) String() string         { return fmt.Sprintf("<%s, %s>", c.Before, c.After) }
+func (c BenchCmp) Measured(flag int) bool { return (c.Before.Measured & c.After.Measured & flag) != 0 }
+func (c BenchCmp) DeltaNsPerOp() Delta    { return Delta{c.Before.NsPerOp, c.After.NsPerOp} }
+func (c BenchCmp) DeltaMBPerS() Delta     { return Delta{c.Before.MBPerS, c.After.MBPerS} }
+func (c BenchCmp) DeltaAllocedBytesPerOp() Delta {
+	return Delta{float64(c.Before.AllocedBytesPerOp), float64(c.After.AllocedBytesPerOp)}
+}
+func (c BenchCmp) DeltaAllocsPerOp() Delta {
+	return Delta{float64(c.Before.AllocsPerOp), float64(c.After.AllocsPerOp)}
+}
+
+// Delta is the before and after value for a benchmark measurement.
+// Both must be non-negative.
+type Delta struct {
+	Before float64
+	After  float64
+}
+
+// mag calculates the magnitude of a change, regardless of the direction of
+// the change. mag is intended for sorting and has no independent meaning.
+func (d Delta) mag() float64 {
+	switch {
+	case d.Before != 0 && d.After != 0 && d.Before >= d.After:
+		return d.After / d.Before
+	case d.Before != 0 && d.After != 0 && d.Before < d.After:
+		return d.Before / d.After
+	case d.Before == 0 && d.After == 0:
+		return 1
+	default:
+		// 0 -> 1 or 1 -> 0
+		// These are significant changes and worth surfacing.
+		return math.Inf(1)
+	}
+}
+
+// Changed reports whether the benchmark quantities are different.
+func (d Delta) Changed() bool { return d.Before != d.After }
+
+// Float64 returns After / Before. If Before is 0, Float64 returns
+// 1 if After is also 0, and +Inf otherwise.
+func (d Delta) Float64() float64 {
+	switch {
+	case d.Before != 0:
+		return d.After / d.Before
+	case d.After == 0:
+		return 1
+	default:
+		return math.Inf(1)
+	}
+}
+
+// Percent formats a Delta as a percent change, ranging from -100% up.
+func (d Delta) Percent() string {
+	return fmt.Sprintf("%+.2f%%", 100*d.Float64()-100)
+}
+
+// Multiple formats a Delta as a multiplier, ranging from 0.00x up.
+func (d Delta) Multiple() string {
+	return fmt.Sprintf("%.2fx", d.Float64())
+}
+
+func (d Delta) String() string {
+	return fmt.Sprintf("Δ(%f, %f)", d.Before, d.After)
+}
+
+// ByParseOrder sorts BenchCmps to match the order in
+// which the Before benchmarks were presented to Parse.
+type ByParseOrder []BenchCmp
+
+func (x ByParseOrder) Len() int           { return len(x) }
+func (x ByParseOrder) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (x ByParseOrder) Less(i, j int) bool { return x[i].Before.Ord < x[j].Before.Ord }
+
+// lessByDelta provides lexicographic ordering:
+//   * largest delta by magnitude
+//   * alphabetic by name
+func lessByDelta(i, j BenchCmp, calcDelta func(BenchCmp) Delta) bool {
+	iDelta, jDelta := calcDelta(i).mag(), calcDelta(j).mag()
+	if iDelta != jDelta {
+		return iDelta < jDelta
+	}
+	return i.Name() < j.Name()
+}
+
+// ByDeltaNsPerOp sorts BenchCmps lexicographically by change
+// in ns/op, descending, then by benchmark name.
+type ByDeltaNsPerOp []BenchCmp
+
+func (x ByDeltaNsPerOp) Len() int           { return len(x) }
+func (x ByDeltaNsPerOp) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (x ByDeltaNsPerOp) Less(i, j int) bool { return lessByDelta(x[i], x[j], BenchCmp.DeltaNsPerOp) }
+
+// ByDeltaMBPerS sorts BenchCmps lexicographically by change
+// in MB/s, descending, then by benchmark name.
+type ByDeltaMBPerS []BenchCmp
+
+func (x ByDeltaMBPerS) Len() int           { return len(x) }
+func (x ByDeltaMBPerS) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (x ByDeltaMBPerS) Less(i, j int) bool { return lessByDelta(x[i], x[j], BenchCmp.DeltaMBPerS) }
+
+// ByDeltaAllocedBytesPerOp sorts BenchCmps lexicographically by change
+// in B/op, descending, then by benchmark name.
+type ByDeltaAllocedBytesPerOp []BenchCmp
+
+func (x ByDeltaAllocedBytesPerOp) Len() int      { return len(x) }
+func (x ByDeltaAllocedBytesPerOp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x ByDeltaAllocedBytesPerOp) Less(i, j int) bool {
+	return lessByDelta(x[i], x[j], BenchCmp.DeltaAllocedBytesPerOp)
+}
+
+// ByDeltaAllocsPerOp sorts BenchCmps lexicographically by change
+// in allocs/op, descending, then by benchmark name.
+type ByDeltaAllocsPerOp []BenchCmp
+
+func (x ByDeltaAllocsPerOp) Len() int      { return len(x) }
+func (x ByDeltaAllocsPerOp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x ByDeltaAllocsPerOp) Less(i, j int) bool {
+	return lessByDelta(x[i], x[j], BenchCmp.DeltaAllocsPerOp)
+}
diff --git a/cmd/benchcmp/compare_test.go b/cmd/benchcmp/compare_test.go
new file mode 100644
index 0000000..3403796
--- /dev/null
+++ b/cmd/benchcmp/compare_test.go
@@ -0,0 +1,133 @@
+// Copyright 2014 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 main
+
+import (
+	"math"
+	"reflect"
+	"sort"
+	"testing"
+
+	"golang.org/x/tools/benchmark/parse"
+)
+
+func TestDelta(t *testing.T) {
+	cases := []struct {
+		before  float64
+		after   float64
+		mag     float64
+		f       float64
+		changed bool
+		pct     string
+		mult    string
+	}{
+		{before: 1, after: 1, mag: 1, f: 1, changed: false, pct: "+0.00%", mult: "1.00x"},
+		{before: 1, after: 2, mag: 0.5, f: 2, changed: true, pct: "+100.00%", mult: "2.00x"},
+		{before: 2, after: 1, mag: 0.5, f: 0.5, changed: true, pct: "-50.00%", mult: "0.50x"},
+		{before: 0, after: 0, mag: 1, f: 1, changed: false, pct: "+0.00%", mult: "1.00x"},
+		{before: 1, after: 0, mag: math.Inf(1), f: 0, changed: true, pct: "-100.00%", mult: "0.00x"},
+		{before: 0, after: 1, mag: math.Inf(1), f: math.Inf(1), changed: true, pct: "+Inf%", mult: "+Infx"},
+	}
+	for _, tt := range cases {
+		d := Delta{tt.before, tt.after}
+		if want, have := tt.mag, d.mag(); want != have {
+			t.Errorf("%s.mag(): want %f have %f", d, want, have)
+		}
+		if want, have := tt.f, d.Float64(); want != have {
+			t.Errorf("%s.Float64(): want %f have %f", d, want, have)
+		}
+		if want, have := tt.changed, d.Changed(); want != have {
+			t.Errorf("%s.Changed(): want %t have %t", d, want, have)
+		}
+		if want, have := tt.pct, d.Percent(); want != have {
+			t.Errorf("%s.Percent(): want %q have %q", d, want, have)
+		}
+		if want, have := tt.mult, d.Multiple(); want != have {
+			t.Errorf("%s.Multiple(): want %q have %q", d, want, have)
+		}
+	}
+}
+
+func TestCorrelate(t *testing.T) {
+	// Benches that are going to be successfully correlated get N thus:
+	//   0x<counter><num benches><b = before | a = after>
+	// Read this: "<counter> of <num benches>, from <before|after>".
+	before := parse.Set{
+		"BenchmarkOneEach":   []*parse.Benchmark{{Name: "BenchmarkOneEach", N: 0x11b}},
+		"BenchmarkOneToNone": []*parse.Benchmark{{Name: "BenchmarkOneToNone"}},
+		"BenchmarkOneToTwo":  []*parse.Benchmark{{Name: "BenchmarkOneToTwo"}},
+		"BenchmarkTwoToOne": []*parse.Benchmark{
+			{Name: "BenchmarkTwoToOne"},
+			{Name: "BenchmarkTwoToOne"},
+		},
+		"BenchmarkTwoEach": []*parse.Benchmark{
+			{Name: "BenchmarkTwoEach", N: 0x12b},
+			{Name: "BenchmarkTwoEach", N: 0x22b},
+		},
+	}
+
+	after := parse.Set{
+		"BenchmarkOneEach":   []*parse.Benchmark{{Name: "BenchmarkOneEach", N: 0x11a}},
+		"BenchmarkNoneToOne": []*parse.Benchmark{{Name: "BenchmarkNoneToOne"}},
+		"BenchmarkTwoToOne":  []*parse.Benchmark{{Name: "BenchmarkTwoToOne"}},
+		"BenchmarkOneToTwo": []*parse.Benchmark{
+			{Name: "BenchmarkOneToTwo"},
+			{Name: "BenchmarkOneToTwo"},
+		},
+		"BenchmarkTwoEach": []*parse.Benchmark{
+			{Name: "BenchmarkTwoEach", N: 0x12a},
+			{Name: "BenchmarkTwoEach", N: 0x22a},
+		},
+	}
+
+	pairs, errs := Correlate(before, after)
+
+	// Fail to match: BenchmarkOneToNone, BenchmarkOneToTwo, BenchmarkTwoToOne.
+	// Correlate does not notice BenchmarkNoneToOne.
+	if len(errs) != 3 {
+		t.Errorf("Correlated expected 4 errors, got %d: %v", len(errs), errs)
+	}
+
+	// Want three correlated pairs: one BenchmarkOneEach, two BenchmarkTwoEach.
+	if len(pairs) != 3 {
+		t.Fatalf("Correlated expected 3 pairs, got %v", pairs)
+	}
+
+	for _, pair := range pairs {
+		if pair.Before.N&0xF != 0xb {
+			t.Errorf("unexpected Before in pair %s", pair)
+		}
+		if pair.After.N&0xF != 0xa {
+			t.Errorf("unexpected After in pair %s", pair)
+		}
+		if pair.Before.N>>4 != pair.After.N>>4 {
+			t.Errorf("mismatched pair %s", pair)
+		}
+	}
+}
+
+func TestBenchCmpSorting(t *testing.T) {
+	c := []BenchCmp{
+		{&parse.Benchmark{Name: "BenchmarkMuchFaster", NsPerOp: 10, Ord: 3}, &parse.Benchmark{Name: "BenchmarkMuchFaster", NsPerOp: 1}},
+		{&parse.Benchmark{Name: "BenchmarkSameB", NsPerOp: 5, Ord: 1}, &parse.Benchmark{Name: "BenchmarkSameB", NsPerOp: 5}},
+		{&parse.Benchmark{Name: "BenchmarkSameA", NsPerOp: 5, Ord: 2}, &parse.Benchmark{Name: "BenchmarkSameA", NsPerOp: 5}},
+		{&parse.Benchmark{Name: "BenchmarkSlower", NsPerOp: 10, Ord: 0}, &parse.Benchmark{Name: "BenchmarkSlower", NsPerOp: 11}},
+	}
+
+	// Test just one magnitude-based sort order; they are symmetric.
+	sort.Sort(ByDeltaNsPerOp(c))
+	want := []string{"BenchmarkMuchFaster", "BenchmarkSlower", "BenchmarkSameA", "BenchmarkSameB"}
+	have := []string{c[0].Name(), c[1].Name(), c[2].Name(), c[3].Name()}
+	if !reflect.DeepEqual(want, have) {
+		t.Errorf("ByDeltaNsOp incorrect sorting: want %v have %v", want, have)
+	}
+
+	sort.Sort(ByParseOrder(c))
+	want = []string{"BenchmarkSlower", "BenchmarkSameB", "BenchmarkSameA", "BenchmarkMuchFaster"}
+	have = []string{c[0].Name(), c[1].Name(), c[2].Name(), c[3].Name()}
+	if !reflect.DeepEqual(want, have) {
+		t.Errorf("ByParseOrder incorrect sorting: want %v have %v", want, have)
+	}
+}
diff --git a/cmd/benchcmp/doc.go b/cmd/benchcmp/doc.go
new file mode 100644
index 0000000..f5c7a36
--- /dev/null
+++ b/cmd/benchcmp/doc.go
@@ -0,0 +1,37 @@
+// Copyright 2014 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 benchcmp command displays performance changes between benchmarks.
+
+Benchcmp parses the output of two 'go test' benchmark runs,
+correlates the results per benchmark, and displays the deltas.
+
+To measure the performance impact of a change, use 'go test'
+to run benchmarks before and after the change:
+
+	go test -run=NONE -bench=. ./... > old.txt
+	# make changes
+	go test -run=NONE -bench=. ./... > new.txt
+
+Then feed the benchmark results to benchcmp:
+
+	benchcmp old.txt new.txt
+
+Benchcmp will summarize and display the performance changes,
+in a format like this:
+
+	$ benchcmp old.txt new.txt
+	benchmark           old ns/op     new ns/op     delta
+	BenchmarkConcat     523           68.6          -86.88%
+
+	benchmark           old allocs     new allocs     delta
+	BenchmarkConcat     3              1              -66.67%
+
+	benchmark           old bytes     new bytes     delta
+	BenchmarkConcat     80            48            -40.00%
+
+*/
+package main // import "golang.org/x/tools/cmd/benchcmp"
diff --git a/cmd/callgraph/main.go b/cmd/callgraph/main.go
new file mode 100644
index 0000000..29179dd
--- /dev/null
+++ b/cmd/callgraph/main.go
@@ -0,0 +1,337 @@
+// Copyright 2014 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.
+
+// callgraph: a tool for reporting the call graph of a Go program.
+// See Usage for details, or run with -help.
+package main // import "golang.org/x/tools/cmd/callgraph"
+
+// TODO(adonovan):
+//
+// Features:
+// - restrict graph to a single package
+// - output
+//   - functions reachable from root (use digraph tool?)
+//   - unreachable functions (use digraph tool?)
+//   - dynamic (runtime) types
+//   - indexed output (numbered nodes)
+//   - JSON output
+//   - additional template fields:
+//     callee file/line/col
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/build"
+	"go/token"
+	"io"
+	"os"
+	"runtime"
+	"text/template"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/go/callgraph"
+	"golang.org/x/tools/go/callgraph/cha"
+	"golang.org/x/tools/go/callgraph/rta"
+	"golang.org/x/tools/go/callgraph/static"
+	"golang.org/x/tools/go/loader"
+	"golang.org/x/tools/go/pointer"
+	"golang.org/x/tools/go/ssa"
+	"golang.org/x/tools/go/ssa/ssautil"
+)
+
+var algoFlag = flag.String("algo", "rta",
+	`Call graph construction algorithm (static, cha, rta, pta)`)
+
+var testFlag = flag.Bool("test", false,
+	"Loads test code (*_test.go) for imported packages")
+
+var formatFlag = flag.String("format",
+	"{{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}",
+	"A template expression specifying how to format an edge")
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const Usage = `callgraph: display the the call graph of a Go program.
+
+Usage:
+
+  callgraph [-algo=static|cha|rta|pta] [-test] [-format=...] <args>...
+
+Flags:
+
+-algo      Specifies the call-graph construction algorithm, one of:
+
+            static      static calls only (unsound)
+            cha         Class Hierarchy Analysis
+            rta         Rapid Type Analysis
+            pta         inclusion-based Points-To Analysis
+
+           The algorithms are ordered by increasing precision in their
+           treatment of dynamic calls (and thus also computational cost).
+           RTA and PTA require a whole program (main or test), and
+           include only functions reachable from main.
+
+-test      Include the package's tests in the analysis.
+
+-format    Specifies the format in which each call graph edge is displayed.
+           One of:
+
+            digraph     output suitable for input to
+                        golang.org/x/tools/cmd/digraph.
+            graphviz    output in AT&T GraphViz (.dot) format.
+
+           All other values are interpreted using text/template syntax.
+           The default value is:
+
+            {{.Caller}}\t--{{.Dynamic}}-{{.Line}}:{{.Column}}-->\t{{.Callee}}
+
+           The structure passed to the template is (effectively):
+
+                   type Edge struct {
+                           Caller      *ssa.Function // calling function
+                           Callee      *ssa.Function // called function
+
+                           // Call site:
+                           Filename    string // containing file
+                           Offset      int    // offset within file of '('
+                           Line        int    // line number
+                           Column      int    // column number of call
+                           Dynamic     string // "static" or "dynamic"
+                           Description string // e.g. "static method call"
+                   }
+
+           Caller and Callee are *ssa.Function values, which print as
+           "(*sync/atomic.Mutex).Lock", but other attributes may be
+           derived from them, e.g. Caller.Pkg.Object.Path yields the
+           import path of the enclosing package.  Consult the go/ssa
+           API documentation for details.
+
+` + loader.FromArgsUsage + `
+
+Examples:
+
+  Show the call graph of the trivial web server application:
+
+    callgraph -format digraph $GOROOT/src/net/http/triv.go
+
+  Same, but show only the packages of each function:
+
+    callgraph -format '{{.Caller.Pkg.Object.Path}} -> {{.Callee.Pkg.Object.Path}}' \
+      $GOROOT/src/net/http/triv.go | sort | uniq
+
+  Show functions that make dynamic calls into the 'fmt' test package,
+  using the pointer analysis algorithm:
+
+    callgraph -format='{{.Caller}} -{{.Dynamic}}-> {{.Callee}}' -test -algo=pta fmt |
+      sed -ne 's/-dynamic-/--/p' |
+      sed -ne 's/-->.*fmt_test.*$//p' | sort | uniq
+
+  Show all functions directly called by the callgraph tool's main function:
+
+    callgraph -format=digraph golang.org/x/tools/cmd/callgraph |
+      digraph succs golang.org/x/tools/cmd/callgraph.main
+`
+
+func init() {
+	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
+	// For small machines, use at least 4 threads.
+	if os.Getenv("GOMAXPROCS") == "" {
+		n := runtime.NumCPU()
+		if n < 4 {
+			n = 4
+		}
+		runtime.GOMAXPROCS(n)
+	}
+}
+
+func main() {
+	flag.Parse()
+	if err := doCallgraph(&build.Default, *algoFlag, *formatFlag, *testFlag, flag.Args()); err != nil {
+		fmt.Fprintf(os.Stderr, "callgraph: %s\n", err)
+		os.Exit(1)
+	}
+}
+
+var stdout io.Writer = os.Stdout
+
+func doCallgraph(ctxt *build.Context, algo, format string, tests bool, args []string) error {
+	conf := loader.Config{Build: ctxt}
+
+	if len(args) == 0 {
+		fmt.Fprintln(os.Stderr, Usage)
+		return nil
+	}
+
+	// Use the initial packages from the command line.
+	args, err := conf.FromArgs(args, tests)
+	if err != nil {
+		return err
+	}
+
+	// Load, parse and type-check the whole program.
+	iprog, err := conf.Load()
+	if err != nil {
+		return err
+	}
+
+	// Create and build SSA-form program representation.
+	prog := ssautil.CreateProgram(iprog, 0)
+	prog.BuildAll()
+
+	// -- call graph construction ------------------------------------------
+
+	var cg *callgraph.Graph
+
+	switch algo {
+	case "static":
+		cg = static.CallGraph(prog)
+
+	case "cha":
+		cg = cha.CallGraph(prog)
+
+	case "pta":
+		main, err := mainPackage(prog, tests)
+		if err != nil {
+			return err
+		}
+		config := &pointer.Config{
+			Mains:          []*ssa.Package{main},
+			BuildCallGraph: true,
+		}
+		ptares, err := pointer.Analyze(config)
+		if err != nil {
+			return err // internal error in pointer analysis
+		}
+		cg = ptares.CallGraph
+
+	case "rta":
+		main, err := mainPackage(prog, tests)
+		if err != nil {
+			return err
+		}
+		roots := []*ssa.Function{
+			main.Func("init"),
+			main.Func("main"),
+		}
+		rtares := rta.Analyze(roots, true)
+		cg = rtares.CallGraph
+
+		// NB: RTA gives us Reachable and RuntimeTypes too.
+
+	default:
+		return fmt.Errorf("unknown algorithm: %s", algo)
+	}
+
+	cg.DeleteSyntheticNodes()
+
+	// -- output------------------------------------------------------------
+
+	var before, after string
+
+	// Pre-canned formats.
+	switch format {
+	case "digraph":
+		format = `{{printf "%q %q" .Caller .Callee}}`
+
+	case "graphviz":
+		before = "digraph callgraph {\n"
+		after = "}\n"
+		format = `  {{printf "%q" .Caller}} -> {{printf "%q" .Callee}}`
+	}
+
+	tmpl, err := template.New("-format").Parse(format)
+	if err != nil {
+		return fmt.Errorf("invalid -format template: %v", err)
+	}
+
+	// Allocate these once, outside the traversal.
+	var buf bytes.Buffer
+	data := Edge{fset: prog.Fset}
+
+	fmt.Fprint(stdout, before)
+	if err := callgraph.GraphVisitEdges(cg, func(edge *callgraph.Edge) error {
+		data.position.Offset = -1
+		data.edge = edge
+		data.Caller = edge.Caller.Func
+		data.Callee = edge.Callee.Func
+
+		buf.Reset()
+		if err := tmpl.Execute(&buf, &data); err != nil {
+			return err
+		}
+		stdout.Write(buf.Bytes())
+		if len := buf.Len(); len == 0 || buf.Bytes()[len-1] != '\n' {
+			fmt.Fprintln(stdout)
+		}
+		return nil
+	}); err != nil {
+		return err
+	}
+	fmt.Fprint(stdout, after)
+	return nil
+}
+
+// mainPackage returns the main package to analyze.
+// The resulting package has a main() function.
+func mainPackage(prog *ssa.Program, tests bool) (*ssa.Package, error) {
+	pkgs := prog.AllPackages()
+
+	// TODO(adonovan): allow independent control over tests, mains and libraries.
+	// TODO(adonovan): put this logic in a library; we keep reinventing it.
+
+	if tests {
+		// If -test, use all packages' tests.
+		if len(pkgs) > 0 {
+			if main := prog.CreateTestMainPackage(pkgs...); main != nil {
+				return main, nil
+			}
+		}
+		return nil, fmt.Errorf("no tests")
+	}
+
+	// Otherwise, use the first package named main.
+	for _, pkg := range pkgs {
+		if pkg.Object.Name() == "main" {
+			if pkg.Func("main") == nil {
+				return nil, fmt.Errorf("no func main() in main package")
+			}
+			return pkg, nil
+		}
+	}
+
+	return nil, fmt.Errorf("no main package")
+}
+
+type Edge struct {
+	Caller *ssa.Function
+	Callee *ssa.Function
+
+	edge     *callgraph.Edge
+	fset     *token.FileSet
+	position token.Position // initialized lazily
+}
+
+func (e *Edge) pos() *token.Position {
+	if e.position.Offset == -1 {
+		e.position = e.fset.Position(e.edge.Pos()) // called lazily
+	}
+	return &e.position
+}
+
+func (e *Edge) Filename() string { return e.pos().Filename }
+func (e *Edge) Column() int      { return e.pos().Column }
+func (e *Edge) Line() int        { return e.pos().Line }
+func (e *Edge) Offset() int      { return e.pos().Offset }
+
+func (e *Edge) Dynamic() string {
+	if e.edge.Site != nil && e.edge.Site.Common().StaticCallee() == nil {
+		return "dynamic"
+	}
+	return "static"
+}
+
+func (e *Edge) Description() string { return e.edge.Description() }
diff --git a/cmd/callgraph/main_test.go b/cmd/callgraph/main_test.go
new file mode 100644
index 0000000..f1f7166
--- /dev/null
+++ b/cmd/callgraph/main_test.go
@@ -0,0 +1,81 @@
+// Copyright 2014 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.
+
+// No testdata on Android.
+
+// +build !android
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/build"
+	"reflect"
+	"sort"
+	"strings"
+	"testing"
+)
+
+func TestCallgraph(t *testing.T) {
+	ctxt := build.Default // copy
+	ctxt.GOPATH = "testdata"
+
+	const format = "{{.Caller}} --> {{.Callee}}"
+
+	for _, test := range []struct {
+		algo, format string
+		tests        bool
+		want         []string
+	}{
+		{"rta", format, false, []string{
+			// rta imprecisely shows cross product of {main,main2} x {C,D}
+			`pkg.main --> (pkg.C).f`,
+			`pkg.main --> (pkg.D).f`,
+			`pkg.main --> pkg.main2`,
+			`pkg.main2 --> (pkg.C).f`,
+			`pkg.main2 --> (pkg.D).f`,
+		}},
+		{"pta", format, false, []string{
+			// pta distinguishes main->C, main2->D.  Also has a root node.
+			`<root> --> pkg.init`,
+			`<root> --> pkg.main`,
+			`pkg.main --> (pkg.C).f`,
+			`pkg.main --> pkg.main2`,
+			`pkg.main2 --> (pkg.D).f`,
+		}},
+		// tests: main is not called.
+		{"rta", format, true, []string{
+			`pkg.Example --> (pkg.C).f`,
+			`test$main.init --> pkg.init`,
+		}},
+		{"pta", format, true, []string{
+			`<root> --> pkg.Example`,
+			`<root> --> test$main.init`,
+			`pkg.Example --> (pkg.C).f`,
+			`test$main.init --> pkg.init`,
+		}},
+	} {
+		stdout = new(bytes.Buffer)
+		if err := doCallgraph(&ctxt, test.algo, test.format, test.tests, []string{"pkg"}); err != nil {
+			t.Error(err)
+			continue
+		}
+
+		got := sortedLines(fmt.Sprint(stdout))
+		if !reflect.DeepEqual(got, test.want) {
+			t.Errorf("callgraph(%q, %q, %t):\ngot:\n%s\nwant:\n%s",
+				test.algo, test.format, test.tests,
+				strings.Join(got, "\n"),
+				strings.Join(test.want, "\n"))
+		}
+	}
+}
+
+func sortedLines(s string) []string {
+	s = strings.TrimSpace(s)
+	lines := strings.Split(s, "\n")
+	sort.Strings(lines)
+	return lines
+}
diff --git a/cmd/callgraph/testdata/src/pkg/pkg.go b/cmd/callgraph/testdata/src/pkg/pkg.go
new file mode 100644
index 0000000..b81c97f
--- /dev/null
+++ b/cmd/callgraph/testdata/src/pkg/pkg.go
@@ -0,0 +1,25 @@
+package main
+
+type I interface {
+	f()
+}
+
+type C int
+
+func (C) f() {}
+
+type D int
+
+func (D) f() {}
+
+func main() {
+	var i I = C(0)
+	i.f() // dynamic call
+
+	main2()
+}
+
+func main2() {
+	var i I = D(0)
+	i.f() // dynamic call
+}
diff --git a/cmd/callgraph/testdata/src/pkg/pkg_test.go b/cmd/callgraph/testdata/src/pkg/pkg_test.go
new file mode 100644
index 0000000..d624757
--- /dev/null
+++ b/cmd/callgraph/testdata/src/pkg/pkg_test.go
@@ -0,0 +1,7 @@
+package main
+
+// Don't import "testing", it adds a lot of callgraph edges.
+
+func Example() {
+	C(0).f()
+}
diff --git a/cmd/cover/README b/cmd/cover/README
new file mode 100644
index 0000000..ff9523d
--- /dev/null
+++ b/cmd/cover/README
@@ -0,0 +1,2 @@
+NOTE: For Go releases 1.5 and later, this tool lives in the
+standard repository. The code here is not maintained.
diff --git a/cmd/cover/cover.go b/cmd/cover/cover.go
new file mode 100644
index 0000000..31ec434
--- /dev/null
+++ b/cmd/cover/cover.go
@@ -0,0 +1,722 @@
+// Copyright 2013 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 main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+const usageMessage = "" +
+	`Usage of 'go tool cover':
+Given a coverage profile produced by 'go test':
+	go test -coverprofile=c.out
+
+Open a web browser displaying annotated source code:
+	go tool cover -html=c.out
+
+Write out an HTML file instead of launching a web browser:
+	go tool cover -html=c.out -o coverage.html
+
+Display coverage percentages to stdout for each function:
+	go tool cover -func=c.out
+
+Finally, to generate modified source code with coverage annotations
+(what go test -cover does):
+	go tool cover -mode=set -var=CoverageVariableName program.go
+`
+
+func usage() {
+	fmt.Fprintln(os.Stderr, usageMessage)
+	fmt.Fprintln(os.Stderr, "Flags:")
+	flag.PrintDefaults()
+	fmt.Fprintln(os.Stderr, "\n  Only one of -html, -func, or -mode may be set.")
+	os.Exit(2)
+}
+
+var (
+	mode    = flag.String("mode", "", "coverage mode: set, count, atomic")
+	varVar  = flag.String("var", "GoCover", "name of coverage variable to generate")
+	output  = flag.String("o", "", "file for output; default: stdout")
+	htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
+	funcOut = flag.String("func", "", "output coverage profile information for each function")
+)
+
+var profile string // The profile to read; the value of -html or -func
+
+var counterStmt func(*File, ast.Expr) ast.Stmt
+
+const (
+	atomicPackagePath = "sync/atomic"
+	atomicPackageName = "_cover_atomic_"
+)
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	// Usage information when no arguments.
+	if flag.NFlag() == 0 && flag.NArg() == 0 {
+		flag.Usage()
+	}
+
+	err := parseFlags()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`)
+		os.Exit(2)
+	}
+
+	// Generate coverage-annotated source.
+	if *mode != "" {
+		annotate(flag.Arg(0))
+		return
+	}
+
+	// Output HTML or function coverage information.
+	if *htmlOut != "" {
+		err = htmlOutput(profile, *output)
+	} else {
+		err = funcOutput(profile, *output)
+	}
+
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "cover: %v\n", err)
+		os.Exit(2)
+	}
+}
+
+// parseFlags sets the profile and counterStmt globals and performs validations.
+func parseFlags() error {
+	profile = *htmlOut
+	if *funcOut != "" {
+		if profile != "" {
+			return fmt.Errorf("too many options")
+		}
+		profile = *funcOut
+	}
+
+	// Must either display a profile or rewrite Go source.
+	if (profile == "") == (*mode == "") {
+		return fmt.Errorf("too many options")
+	}
+
+	if *mode != "" {
+		switch *mode {
+		case "set":
+			counterStmt = setCounterStmt
+		case "count":
+			counterStmt = incCounterStmt
+		case "atomic":
+			counterStmt = atomicCounterStmt
+		default:
+			return fmt.Errorf("unknown -mode %v", *mode)
+		}
+
+		if flag.NArg() == 0 {
+			return fmt.Errorf("missing source file")
+		} else if flag.NArg() == 1 {
+			return nil
+		}
+	} else if flag.NArg() == 0 {
+		return nil
+	}
+	return fmt.Errorf("too many arguments")
+}
+
+// Block represents the information about a basic block to be recorded in the analysis.
+// Note: Our definition of basic block is based on control structures; we don't break
+// apart && and ||. We could but it doesn't seem important enough to bother.
+type Block struct {
+	startByte token.Pos
+	endByte   token.Pos
+	numStmt   int
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The basic parse tree walker is a method of this type.
+type File struct {
+	fset      *token.FileSet
+	name      string // Name of file.
+	astFile   *ast.File
+	blocks    []Block
+	atomicPkg string // Package name for "sync/atomic" in this file.
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.BlockStmt:
+		// If it's a switch or select, the body is a list of case clauses; don't tag the block itself.
+		if len(n.List) > 0 {
+			switch n.List[0].(type) {
+			case *ast.CaseClause: // switch
+				for _, n := range n.List {
+					clause := n.(*ast.CaseClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			case *ast.CommClause: // select
+				for _, n := range n.List {
+					clause := n.(*ast.CommClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			}
+		}
+		n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
+	case *ast.IfStmt:
+		ast.Walk(f, n.Body)
+		if n.Else == nil {
+			return nil
+		}
+		// The elses are special, because if we have
+		//	if x {
+		//	} else if y {
+		//	}
+		// we want to cover the "if y". To do this, we need a place to drop the counter,
+		// so we add a hidden block:
+		//	if x {
+		//	} else {
+		//		if y {
+		//		}
+		//	}
+		switch stmt := n.Else.(type) {
+		case *ast.IfStmt:
+			block := &ast.BlockStmt{
+				Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
+				List:   []ast.Stmt{stmt},
+				Rbrace: stmt.End(),
+			}
+			n.Else = block
+		case *ast.BlockStmt:
+			stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
+		default:
+			panic("unexpected node type in if")
+		}
+		ast.Walk(f, n.Else)
+		return nil
+	case *ast.SelectStmt:
+		// Don't annotate an empty select - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.SwitchStmt:
+		// Don't annotate an empty switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.TypeSwitchStmt:
+		// Don't annotate an empty type switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	}
+	return f
+}
+
+// unquote returns the unquoted string.
+func unquote(s string) string {
+	t, err := strconv.Unquote(s)
+	if err != nil {
+		log.Fatalf("cover: improperly quoted string %q\n", s)
+	}
+	return t
+}
+
+// addImport adds an import for the specified path, if one does not already exist, and returns
+// the local package name.
+func (f *File) addImport(path string) string {
+	// Does the package already import it?
+	for _, s := range f.astFile.Imports {
+		if unquote(s.Path.Value) == path {
+			if s.Name != nil {
+				return s.Name.Name
+			}
+			return filepath.Base(path)
+		}
+	}
+	newImport := &ast.ImportSpec{
+		Name: ast.NewIdent(atomicPackageName),
+		Path: &ast.BasicLit{
+			Kind:  token.STRING,
+			Value: fmt.Sprintf("%q", path),
+		},
+	}
+	impDecl := &ast.GenDecl{
+		Tok: token.IMPORT,
+		Specs: []ast.Spec{
+			newImport,
+		},
+	}
+	// Make the new import the first Decl in the file.
+	astFile := f.astFile
+	astFile.Decls = append(astFile.Decls, nil)
+	copy(astFile.Decls[1:], astFile.Decls[0:])
+	astFile.Decls[0] = impDecl
+	astFile.Imports = append(astFile.Imports, newImport)
+
+	// Now refer to the package, just in case it ends up unused.
+	// That is, append to the end of the file the declaration
+	//	var _ = _cover_atomic_.AddUint32
+	reference := &ast.GenDecl{
+		Tok: token.VAR,
+		Specs: []ast.Spec{
+			&ast.ValueSpec{
+				Names: []*ast.Ident{
+					ast.NewIdent("_"),
+				},
+				Values: []ast.Expr{
+					&ast.SelectorExpr{
+						X:   ast.NewIdent(atomicPackageName),
+						Sel: ast.NewIdent("AddUint32"),
+					},
+				},
+			},
+		},
+	}
+	astFile.Decls = append(astFile.Decls, reference)
+	return atomicPackageName
+}
+
+var slashslash = []byte("//")
+
+// initialComments returns the prefix of content containing only
+// whitespace and line comments.  Any +build directives must appear
+// within this region.  This approach is more reliable than using
+// go/printer to print a modified AST containing comments.
+//
+func initialComments(content []byte) []byte {
+	// Derived from go/build.Context.shouldBuild.
+	end := 0
+	p := content
+	for len(p) > 0 {
+		line := p
+		if i := bytes.IndexByte(line, '\n'); i >= 0 {
+			line, p = line[:i], p[i+1:]
+		} else {
+			p = p[len(p):]
+		}
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 { // Blank line.
+			end = len(content) - len(p)
+			continue
+		}
+		if !bytes.HasPrefix(line, slashslash) { // Not comment line.
+			break
+		}
+	}
+	return content[:end]
+}
+
+func annotate(name string) {
+	fset := token.NewFileSet()
+	content, err := ioutil.ReadFile(name)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile.Comments = trimComments(parsedFile, fset)
+
+	file := &File{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	if *mode == "atomic" {
+		file.atomicPkg = file.addImport(atomicPackagePath)
+	}
+	ast.Walk(file, file.astFile)
+	fd := os.Stdout
+	if *output != "" {
+		var err error
+		fd, err = os.Create(*output)
+		if err != nil {
+			log.Fatalf("cover: %s", err)
+		}
+	}
+	fd.Write(initialComments(content)) // Retain '// +build' directives.
+	file.print(fd)
+	// After printing the source tree, add some declarations for the counters etc.
+	// We could do this by adding to the tree, but it's easier just to print the text.
+	file.addVariables(fd)
+}
+
+// trimComments drops all but the //go: comments, some of which are semantically important.
+// We drop all others because they can appear in places that cause our counters
+// to appear in syntactically incorrect places. //go: appears at the beginning of
+// the line and is syntactically safe.
+func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
+	var comments []*ast.CommentGroup
+	for _, group := range file.Comments {
+		var list []*ast.Comment
+		for _, comment := range group.List {
+			if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
+				list = append(list, comment)
+			}
+		}
+		if list != nil {
+			comments = append(comments, &ast.CommentGroup{list})
+		}
+	}
+	return comments
+}
+
+func (f *File) print(w io.Writer) {
+	printer.Fprint(w, f.fset, f.astFile)
+}
+
+// intLiteral returns an ast.BasicLit representing the integer value.
+func (f *File) intLiteral(i int) *ast.BasicLit {
+	node := &ast.BasicLit{
+		Kind:  token.INT,
+		Value: fmt.Sprint(i),
+	}
+	return node
+}
+
+// index returns an ast.BasicLit representing the number of counters present.
+func (f *File) index() *ast.BasicLit {
+	return f.intLiteral(len(f.blocks))
+}
+
+// setCounterStmt returns the expression: __count[23] = 1.
+func setCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.AssignStmt{
+		Lhs: []ast.Expr{counter},
+		Tok: token.ASSIGN,
+		Rhs: []ast.Expr{f.intLiteral(1)},
+	}
+}
+
+// incCounterStmt returns the expression: __count[23]++.
+func incCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.IncDecStmt{
+		X:   counter,
+		Tok: token.INC,
+	}
+}
+
+// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1)
+func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.ExprStmt{
+		X: &ast.CallExpr{
+			Fun: &ast.SelectorExpr{
+				X:   ast.NewIdent(f.atomicPkg),
+				Sel: ast.NewIdent("AddUint32"),
+			},
+			Args: []ast.Expr{&ast.UnaryExpr{
+				Op: token.AND,
+				X:  counter,
+			},
+				f.intLiteral(1),
+			},
+		},
+	}
+}
+
+// newCounter creates a new counter expression of the appropriate form.
+func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt {
+	counter := &ast.IndexExpr{
+		X: &ast.SelectorExpr{
+			X:   ast.NewIdent(*varVar),
+			Sel: ast.NewIdent("Count"),
+		},
+		Index: f.index(),
+	}
+	stmt := counterStmt(f, counter)
+	f.blocks = append(f.blocks, Block{start, end, numStmt})
+	return stmt
+}
+
+// addCounters takes a list of statements and adds counters to the beginning of
+// each basic block at the top level of that list. For instance, given
+//
+//	S1
+//	if cond {
+//		S2
+// 	}
+//	S3
+//
+// counters will be added before S1 and before S3. The block containing S2
+// will be visited in a separate call.
+// TODO: Nested simple blocks get unnecessary (but correct) counters
+func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt {
+	// Special case: make sure we add a counter to an empty block. Can't do this below
+	// or we will add a counter to an empty statement list after, say, a return statement.
+	if len(list) == 0 {
+		return []ast.Stmt{f.newCounter(pos, blockEnd, 0)}
+	}
+	// We have a block (statement list), but it may have several basic blocks due to the
+	// appearance of statements that affect the flow of control.
+	var newList []ast.Stmt
+	for {
+		// Find first statement that affects flow of control (break, continue, if, etc.).
+		// It will be the last statement of this basic block.
+		var last int
+		end := blockEnd
+		for last = 0; last < len(list); last++ {
+			end = f.statementBoundary(list[last])
+			if f.endsBasicSourceBlock(list[last]) {
+				extendToClosingBrace = false // Block is broken up now.
+				last++
+				break
+			}
+		}
+		if extendToClosingBrace {
+			end = blockEnd
+		}
+		if pos != end { // Can have no source to cover if e.g. blocks abut.
+			newList = append(newList, f.newCounter(pos, end, last))
+		}
+		newList = append(newList, list[0:last]...)
+		list = list[last:]
+		if len(list) == 0 {
+			break
+		}
+		pos = list[0].Pos()
+	}
+	return newList
+}
+
+// hasFuncLiteral reports the existence and position of the first func literal
+// in the node, if any. If a func literal appears, it usually marks the termination
+// of a basic block because the function body is itself a block.
+// Therefore we draw a line at the start of the body of the first function literal we find.
+// TODO: what if there's more than one? Probably doesn't matter much.
+func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
+	if n == nil {
+		return false, 0
+	}
+	var literal funcLitFinder
+	ast.Walk(&literal, n)
+	return literal.found(), token.Pos(literal)
+}
+
+// statementBoundary finds the location in s that terminates the current basic
+// block in the source.
+func (f *File) statementBoundary(s ast.Stmt) token.Pos {
+	// Control flow statements are easy.
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return s.Lbrace
+	case *ast.IfStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.ForStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Post)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.LabeledStmt:
+		return f.statementBoundary(s.Stmt)
+	case *ast.RangeStmt:
+		found, pos := hasFuncLiteral(s.X)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Tag)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SelectStmt:
+		return s.Body.Lbrace
+	case *ast.TypeSwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	}
+	// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
+	// If it does, that's tricky because we want to exclude the body of the function from this block.
+	// Draw a line at the start of the body of the first function literal we find.
+	// TODO: what if there's more than one? Probably doesn't matter much.
+	found, pos := hasFuncLiteral(s)
+	if found {
+		return pos
+	}
+	return s.End()
+}
+
+// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc.,
+// or if it's just problematic, for instance contains a function literal, which will complicate
+// accounting due to the block-within-an expression.
+func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return true
+	case *ast.BranchStmt:
+		return true
+	case *ast.ForStmt:
+		return true
+	case *ast.IfStmt:
+		return true
+	case *ast.LabeledStmt:
+		return f.endsBasicSourceBlock(s.Stmt)
+	case *ast.RangeStmt:
+		return true
+	case *ast.SwitchStmt:
+		return true
+	case *ast.SelectStmt:
+		return true
+	case *ast.TypeSwitchStmt:
+		return true
+	case *ast.ExprStmt:
+		// Calls to panic change the flow.
+		// We really should verify that "panic" is the predefined function,
+		// but without type checking we can't and the likelihood of it being
+		// an actual problem is vanishingly small.
+		if call, ok := s.X.(*ast.CallExpr); ok {
+			if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 {
+				return true
+			}
+		}
+	}
+	found, _ := hasFuncLiteral(s)
+	return found
+}
+
+// funcLitFinder implements the ast.Visitor pattern to find the location of any
+// function literal in a subtree.
+type funcLitFinder token.Pos
+
+func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) {
+	if f.found() {
+		return nil // Prune search.
+	}
+	switch n := node.(type) {
+	case *ast.FuncLit:
+		*f = funcLitFinder(n.Body.Lbrace)
+		return nil // Prune search.
+	}
+	return f
+}
+
+func (f *funcLitFinder) found() bool {
+	return token.Pos(*f) != token.NoPos
+}
+
+// Sort interface for []block1; used for self-check in addVariables.
+
+type block1 struct {
+	Block
+	index int
+}
+
+type blockSlice []block1
+
+func (b blockSlice) Len() int           { return len(b) }
+func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte }
+func (b blockSlice) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
+
+// offset translates a token position into a 0-indexed byte offset.
+func (f *File) offset(pos token.Pos) int {
+	return f.fset.Position(pos).Offset
+}
+
+// addVariables adds to the end of the file the declarations to set up the counter and position variables.
+func (f *File) addVariables(w io.Writer) {
+	// Self-check: Verify that the instrumented basic blocks are disjoint.
+	t := make([]block1, len(f.blocks))
+	for i := range f.blocks {
+		t[i].Block = f.blocks[i]
+		t[i].index = i
+	}
+	sort.Sort(blockSlice(t))
+	for i := 1; i < len(t); i++ {
+		if t[i-1].endByte > t[i].startByte {
+			fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index)
+			// Note: error message is in byte positions, not token positions.
+			fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n",
+				f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte),
+				f.name, f.offset(t[i].startByte), f.offset(t[i].endByte))
+		}
+	}
+
+	// Declare the coverage struct as a package-level variable.
+	fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar)
+	fmt.Fprintf(w, "\tCount     [%d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tPos       [3 * %d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tNumStmt   [%d]uint16\n", len(f.blocks))
+	fmt.Fprintf(w, "} {\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks))
+
+	// A nice long list of positions. Each position is encoded as follows to reduce size:
+	// - 32-bit starting line number
+	// - 32-bit ending line number
+	// - (16 bit ending column number << 16) | (16-bit starting column number).
+	for i, block := range f.blocks {
+		start := f.fset.Position(block.startByte)
+		end := f.fset.Position(block.endByte)
+		fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
+	}
+
+	// Close the position array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks))
+
+	// A nice long list of statements-per-block, so we can give a conventional
+	// valuation of "percent covered". To save space, it's a 16-bit number, so we
+	// clamp it if it overflows - won't matter in practice.
+	for i, block := range f.blocks {
+		n := block.numStmt
+		if n > 1<<16-1 {
+			n = 1<<16 - 1
+		}
+		fmt.Fprintf(w, "\t\t%d, // %d\n", n, i)
+	}
+
+	// Close the statements-per-block array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Close the struct initialization.
+	fmt.Fprintf(w, "}\n")
+}
diff --git a/cmd/cover/cover_test.go b/cmd/cover/cover_test.go
new file mode 100644
index 0000000..a18778b
--- /dev/null
+++ b/cmd/cover/cover_test.go
@@ -0,0 +1,94 @@
+// Copyright 2013 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.
+
+// No testdata on Android.
+
+// +build !android
+
+package main_test
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"testing"
+)
+
+const (
+	// Data directory, also the package directory for the test.
+	testdata = "testdata"
+
+	// Binaries we compile.
+	testcover = "./testcover.exe"
+)
+
+var (
+	// Files we use.
+	testMain    = filepath.Join(testdata, "main.go")
+	testTest    = filepath.Join(testdata, "test.go")
+	coverInput  = filepath.Join(testdata, "test_line.go")
+	coverOutput = filepath.Join(testdata, "test_cover.go")
+)
+
+var debug = false // Keeps the rewritten files around if set.
+
+// Run this shell script, but do it in Go so it can be run by "go test".
+//
+//	replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
+// 	go build -o ./testcover
+// 	./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
+//	go run ./testdata/main.go ./testdata/test.go
+//
+func TestCover(t *testing.T) {
+	// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
+	file, err := ioutil.ReadFile(testTest)
+	if err != nil {
+		t.Fatal(err)
+	}
+	lines := bytes.Split(file, []byte("\n"))
+	for i, line := range lines {
+		lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
+	}
+	err = ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// defer removal of test_line.go
+	if !debug {
+		defer os.Remove(coverInput)
+	}
+
+	// go build -o testcover
+	cmd := exec.Command("go", "build", "-o", testcover)
+	run(cmd, t)
+
+	// defer removal of testcover
+	defer os.Remove(testcover)
+
+	// ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
+	cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
+	run(cmd, t)
+
+	// defer removal of ./testdata/test_cover.go
+	if !debug {
+		defer os.Remove(coverOutput)
+	}
+
+	// go run ./testdata/main.go ./testdata/test.go
+	cmd = exec.Command("go", "run", testMain, coverOutput)
+	run(cmd, t)
+}
+
+func run(c *exec.Cmd, t *testing.T) {
+	c.Stdout = os.Stdout
+	c.Stderr = os.Stderr
+	err := c.Run()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/cmd/cover/doc.go b/cmd/cover/doc.go
new file mode 100644
index 0000000..b74d5b3
--- /dev/null
+++ b/cmd/cover/doc.go
@@ -0,0 +1,27 @@
+// Copyright 2013 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.
+
+/*
+Cover is a program for analyzing the coverage profiles generated by
+'go test -coverprofile=cover.out'.
+
+Cover is also used by 'go test -cover' to rewrite the source code with
+annotations to track which parts of each function are executed.
+It operates on one Go source file at a time, computing approximate
+basic block information by studying the source. It is thus more portable
+than binary-rewriting coverage tools, but also a little less capable.
+For instance, it does not probe inside && and || expressions, and can
+be mildly confused by single statements with multiple function literals.
+
+For usage information, please see:
+	go help testflag
+	go tool cover -help
+
+No longer maintained:
+
+For Go releases 1.5 and later, this tool lives in the
+standard repository. The code here is not maintained.
+
+*/
+package main // import "golang.org/x/tools/cmd/cover"
diff --git a/cmd/cover/func.go b/cmd/cover/func.go
new file mode 100644
index 0000000..41d9fce
--- /dev/null
+++ b/cmd/cover/func.go
@@ -0,0 +1,166 @@
+// Copyright 2013 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.
+
+// This file implements the visitor that computes the (line, column)-(line-column) range for each function.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"text/tabwriter"
+
+	"golang.org/x/tools/cover"
+)
+
+// funcOutput takes two file names as arguments, a coverage profile to read as input and an output
+// file to write ("" means to write to standard output). The function reads the profile and produces
+// as output the coverage data broken down by function, like this:
+//
+//	fmt/format.go:30:	init			100.0%
+//	fmt/format.go:57:	clearflags		100.0%
+//	...
+//	fmt/scan.go:1046:	doScan			100.0%
+//	fmt/scan.go:1075:	advance			96.2%
+//	fmt/scan.go:1119:	doScanf			96.8%
+//	total:		(statements)			91.9%
+
+func funcOutput(profile, outputFile string) error {
+	profiles, err := cover.ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var out *bufio.Writer
+	if outputFile == "" {
+		out = bufio.NewWriter(os.Stdout)
+	} else {
+		fd, err := os.Create(outputFile)
+		if err != nil {
+			return err
+		}
+		defer fd.Close()
+		out = bufio.NewWriter(fd)
+	}
+	defer out.Flush()
+
+	tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0)
+	defer tabber.Flush()
+
+	var total, covered int64
+	for _, profile := range profiles {
+		fn := profile.FileName
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		funcs, err := findFuncs(file)
+		if err != nil {
+			return err
+		}
+		// Now match up functions and profile blocks.
+		for _, f := range funcs {
+			c, t := f.coverage(profile)
+			fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
+			total += t
+			covered += c
+		}
+	}
+	fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
+
+	return nil
+}
+
+// findFuncs parses the file and returns a slice of FuncExtent descriptors.
+func findFuncs(name string) ([]*FuncExtent, error) {
+	fset := token.NewFileSet()
+	parsedFile, err := parser.ParseFile(fset, name, nil, 0)
+	if err != nil {
+		return nil, err
+	}
+	visitor := &FuncVisitor{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	ast.Walk(visitor, visitor.astFile)
+	return visitor.funcs, nil
+}
+
+// FuncExtent describes a function's extent in the source by file and position.
+type FuncExtent struct {
+	name      string
+	startLine int
+	startCol  int
+	endLine   int
+	endCol    int
+}
+
+// FuncVisitor implements the visitor that builds the function position list for a file.
+type FuncVisitor struct {
+	fset    *token.FileSet
+	name    string // Name of file.
+	astFile *ast.File
+	funcs   []*FuncExtent
+}
+
+// Visit implements the ast.Visitor interface.
+func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		start := v.fset.Position(n.Pos())
+		end := v.fset.Position(n.End())
+		fe := &FuncExtent{
+			name:      n.Name.Name,
+			startLine: start.Line,
+			startCol:  start.Column,
+			endLine:   end.Line,
+			endCol:    end.Column,
+		}
+		v.funcs = append(v.funcs, fe)
+	}
+	return v
+}
+
+// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator.
+func (f *FuncExtent) coverage(profile *cover.Profile) (num, den int64) {
+	// We could avoid making this n^2 overall by doing a single scan and annotating the functions,
+	// but the sizes of the data structures is never very large and the scan is almost instantaneous.
+	var covered, total int64
+	// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
+	for _, b := range profile.Blocks {
+		if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) {
+			// Past the end of the function.
+			break
+		}
+		if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) {
+			// Before the beginning of the function
+			continue
+		}
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		total = 1 // Avoid zero denominator.
+	}
+	return covered, total
+}
+
+// findFile finds the location of the named file in GOROOT, GOPATH etc.
+func findFile(file string) (string, error) {
+	dir, file := filepath.Split(file)
+	pkg, err := build.Import(dir, ".", build.FindOnly)
+	if err != nil {
+		return "", fmt.Errorf("can't find %q: %v", file, err)
+	}
+	return filepath.Join(pkg.Dir, file), nil
+}
diff --git a/cmd/cover/html.go b/cmd/cover/html.go
new file mode 100644
index 0000000..f6b2264
--- /dev/null
+++ b/cmd/cover/html.go
@@ -0,0 +1,281 @@
+// Copyright 2013 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 main
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+
+	"golang.org/x/tools/cover"
+)
+
+// htmlOutput reads the profile data from profile and generates an HTML
+// coverage report, writing it to outfile. If outfile is empty,
+// it writes the report to a temporary file and opens it in a web browser.
+func htmlOutput(profile, outfile string) error {
+	profiles, err := cover.ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var d templateData
+
+	for _, profile := range profiles {
+		fn := profile.FileName
+		if profile.Mode == "set" {
+			d.Set = true
+		}
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		src, err := ioutil.ReadFile(file)
+		if err != nil {
+			return fmt.Errorf("can't read %q: %v", fn, err)
+		}
+		var buf bytes.Buffer
+		err = htmlGen(&buf, src, profile.Boundaries(src))
+		if err != nil {
+			return err
+		}
+		d.Files = append(d.Files, &templateFile{
+			Name:     fn,
+			Body:     template.HTML(buf.String()),
+			Coverage: percentCovered(profile),
+		})
+	}
+
+	var out *os.File
+	if outfile == "" {
+		var dir string
+		dir, err = ioutil.TempDir("", "cover")
+		if err != nil {
+			return err
+		}
+		out, err = os.Create(filepath.Join(dir, "coverage.html"))
+	} else {
+		out, err = os.Create(outfile)
+	}
+	err = htmlTemplate.Execute(out, d)
+	if err == nil {
+		err = out.Close()
+	}
+	if err != nil {
+		return err
+	}
+
+	if outfile == "" {
+		if !startBrowser("file://" + out.Name()) {
+			fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
+		}
+	}
+
+	return nil
+}
+
+// percentCovered returns, as a percentage, the fraction of the statements in
+// the profile covered by the test run.
+// In effect, it reports the coverage of a given source file.
+func percentCovered(p *cover.Profile) float64 {
+	var total, covered int64
+	for _, b := range p.Blocks {
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		return 0
+	}
+	return float64(covered) / float64(total) * 100
+}
+
+// htmlGen generates an HTML coverage report with the provided filename,
+// source code, and tokens, and writes it to the given Writer.
+func htmlGen(w io.Writer, src []byte, boundaries []cover.Boundary) error {
+	dst := bufio.NewWriter(w)
+	for i := range src {
+		for len(boundaries) > 0 && boundaries[0].Offset == i {
+			b := boundaries[0]
+			if b.Start {
+				n := 0
+				if b.Count > 0 {
+					n = int(math.Floor(b.Norm*9)) + 1
+				}
+				fmt.Fprintf(dst, `<span class="cov%v" title="%v">`, n, b.Count)
+			} else {
+				dst.WriteString("</span>")
+			}
+			boundaries = boundaries[1:]
+		}
+		switch b := src[i]; b {
+		case '>':
+			dst.WriteString("&gt;")
+		case '<':
+			dst.WriteString("&lt;")
+		case '&':
+			dst.WriteString("&amp;")
+		case '\t':
+			dst.WriteString("        ")
+		default:
+			dst.WriteByte(b)
+		}
+	}
+	return dst.Flush()
+}
+
+// startBrowser tries to open the URL in a browser
+// and reports whether it succeeds.
+func startBrowser(url string) bool {
+	// try to start the browser
+	var args []string
+	switch runtime.GOOS {
+	case "darwin":
+		args = []string{"open"}
+	case "windows":
+		args = []string{"cmd", "/c", "start"}
+	default:
+		args = []string{"xdg-open"}
+	}
+	cmd := exec.Command(args[0], append(args[1:], url)...)
+	return cmd.Start() == nil
+}
+
+// rgb returns an rgb value for the specified coverage value
+// between 0 (no coverage) and 10 (max coverage).
+func rgb(n int) string {
+	if n == 0 {
+		return "rgb(192, 0, 0)" // Red
+	}
+	// Gradient from gray to green.
+	r := 128 - 12*(n-1)
+	g := 128 + 12*(n-1)
+	b := 128 + 3*(n-1)
+	return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
+}
+
+// colors generates the CSS rules for coverage colors.
+func colors() template.CSS {
+	var buf bytes.Buffer
+	for i := 0; i < 11; i++ {
+		fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i))
+	}
+	return template.CSS(buf.String())
+}
+
+var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{
+	"colors": colors,
+}).Parse(tmplHTML))
+
+type templateData struct {
+	Files []*templateFile
+	Set   bool
+}
+
+type templateFile struct {
+	Name     string
+	Body     template.HTML
+	Coverage float64
+}
+
+const tmplHTML = `
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<style>
+			body {
+				background: black;
+				color: rgb(80, 80, 80);
+			}
+			body, pre, #legend span {
+				font-family: Menlo, monospace;
+				font-weight: bold;
+			}
+			#topbar {
+				background: black;
+				position: fixed;
+				top: 0; left: 0; right: 0;
+				height: 42px;
+				border-bottom: 1px solid rgb(80, 80, 80);
+			}
+			#content {
+				margin-top: 50px;
+			}
+			#nav, #legend {
+				float: left;
+				margin-left: 10px;
+			}
+			#legend {
+				margin-top: 12px;
+			}
+			#nav {
+				margin-top: 10px;
+			}
+			#legend span {
+				margin: 0 5px;
+			}
+			{{colors}}
+		</style>
+	</head>
+	<body>
+		<div id="topbar">
+			<div id="nav">
+				<select id="files">
+				{{range $i, $f := .Files}}
+				<option value="file{{$i}}">{{$f.Name}} ({{printf "%.1f" $f.Coverage}}%)</option>
+				{{end}}
+				</select>
+			</div>
+			<div id="legend">
+				<span>not tracked</span>
+			{{if .Set}}
+				<span class="cov0">not covered</span>
+				<span class="cov8">covered</span>
+			{{else}}
+				<span class="cov0">no coverage</span>
+				<span class="cov1">low coverage</span>
+				<span class="cov2">*</span>
+				<span class="cov3">*</span>
+				<span class="cov4">*</span>
+				<span class="cov5">*</span>
+				<span class="cov6">*</span>
+				<span class="cov7">*</span>
+				<span class="cov8">*</span>
+				<span class="cov9">*</span>
+				<span class="cov10">high coverage</span>
+			{{end}}
+			</div>
+		</div>
+		<div id="content">
+		{{range $i, $f := .Files}}
+		<pre class="file" id="file{{$i}}" {{if $i}}style="display: none"{{end}}>{{$f.Body}}</pre>
+		{{end}}
+		</div>
+	</body>
+	<script>
+	(function() {
+		var files = document.getElementById('files');
+		var visible = document.getElementById('file0');
+		files.addEventListener('change', onChange, false);
+		function onChange() {
+			visible.style.display = 'none';
+			visible = document.getElementById(files.value);
+			visible.style.display = 'block';
+			window.scrollTo(0, 0);
+		}
+	})();
+	</script>
+</html>
+`
diff --git a/cmd/cover/testdata/main.go b/cmd/cover/testdata/main.go
new file mode 100644
index 0000000..6ed39c4
--- /dev/null
+++ b/cmd/cover/testdata/main.go
@@ -0,0 +1,112 @@
+// Copyright 2013 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.
+
+// Test runner for coverage test. This file is not coverage-annotated; test.go is.
+// It knows the coverage counter is called "coverTest".
+
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func main() {
+	testAll()
+	verify()
+}
+
+type block struct {
+	count uint32
+	line  uint32
+}
+
+var counters = make(map[block]bool)
+
+// check records the location and expected value for a counter.
+func check(line, count uint32) {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+}
+
+// checkVal is a version of check that returns its extra argument,
+// so it can be used in conditionals.
+func checkVal(line, count uint32, val int) int {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+	return val
+}
+
+var PASS = true
+
+// verify checks the expected counts against the actual. It runs after the test has completed.
+func verify() {
+	for b := range counters {
+		got, index := count(b.line)
+		if b.count == anything && got != 0 {
+			got = anything
+		}
+		if got != b.count {
+			fmt.Fprintf(os.Stderr, "test_go:%d expected count %d got %d [counter %d]\n", b.line, b.count, got, index)
+			PASS = false
+		}
+	}
+	verifyPanic()
+	if !PASS {
+		fmt.Fprintf(os.Stderr, "FAIL\n")
+		os.Exit(2)
+	}
+}
+
+// verifyPanic is a special check for the known counter that should be
+// after the panic call in testPanic.
+func verifyPanic() {
+	if coverTest.Count[panicIndex-1] != 1 {
+		// Sanity check for test before panic.
+		fmt.Fprintf(os.Stderr, "bad before panic")
+		PASS = false
+	}
+	if coverTest.Count[panicIndex] != 0 {
+		fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex])
+		PASS = false
+	}
+	if coverTest.Count[panicIndex+1] != 1 {
+		fmt.Fprintf(os.Stderr, "bad after panic")
+		PASS = false
+	}
+}
+
+// count returns the count and index for the counter at the specified line.
+func count(line uint32) (uint32, int) {
+	// Linear search is fine. Choose perfect fit over approximate.
+	// We can have a closing brace for a range on the same line as a condition for an "else if"
+	// and we don't want that brace to steal the count for the condition on the "if".
+	// Therefore we test for a perfect (lo==line && hi==line) match, but if we can't
+	// find that we take the first imperfect match.
+	index := -1
+	indexLo := uint32(1e9)
+	for i := range coverTest.Count {
+		lo, hi := coverTest.Pos[3*i], coverTest.Pos[3*i+1]
+		if lo == line && line == hi {
+			return coverTest.Count[i], i
+		}
+		// Choose the earliest match (the counters are in unpredictable order).
+		if lo <= line && line <= hi && indexLo > lo {
+			index = i
+			indexLo = lo
+		}
+	}
+	if index == -1 {
+		fmt.Fprintln(os.Stderr, "cover_test: no counter for line", line)
+		PASS = false
+		return 0, 0
+	}
+	return coverTest.Count[index], index
+}
diff --git a/cmd/cover/testdata/test.go b/cmd/cover/testdata/test.go
new file mode 100644
index 0000000..9013950
--- /dev/null
+++ b/cmd/cover/testdata/test.go
@@ -0,0 +1,218 @@
+// Copyright 2013 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.
+
+// This program is processed by the cover command, and then testAll is called.
+// The test driver in main.go can then compare the coverage statistics with expectation.
+
+// The word LINE is replaced by the line number in this file. When the file is executed,
+// the coverage processing has changed the line numbers, so we can't use runtime.Caller.
+
+package main
+
+const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
+
+func testAll() {
+	testSimple()
+	testBlockRun()
+	testIf()
+	testFor()
+	testRange()
+	testSwitch()
+	testTypeSwitch()
+	testSelect1()
+	testSelect2()
+	testPanic()
+	testEmptySwitches()
+}
+
+// The indexes of the counters in testPanic are known to main.go
+const panicIndex = 3
+
+// This test appears first because the index of its counters is known to main.go
+func testPanic() {
+	defer func() {
+		recover()
+	}()
+	check(LINE, 1)
+	panic("should not get next line")
+	check(LINE, 0) // this is GoCover.Count[panicIndex]
+	// The next counter is in testSimple and it will be non-zero.
+	// If the panic above does not trigger a counter, the test will fail
+	// because GoCover.Count[panicIndex] will be the one in testSimple.
+}
+
+func testSimple() {
+	check(LINE, 1)
+}
+
+func testIf() {
+	if true {
+		check(LINE, 1)
+	} else {
+		check(LINE, 0)
+	}
+	if false {
+		check(LINE, 0)
+	} else {
+		check(LINE, 1)
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 2 {
+			check(LINE, 3)
+		}
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		}
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		} else {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 2, i) <= 1 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 1, i) <= 2 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 0, i) <= 3 {
+			check(LINE, 0)
+		}
+	}
+	if func(a, b int) bool { return a < b }(3, 4) {
+		check(LINE, 1)
+	}
+}
+
+func testFor() {
+	for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
+		check(LINE, 10)
+	}
+}
+
+func testRange() {
+	for _, f := range []func(){
+		func() { check(LINE, 1) },
+	} {
+		f()
+		check(LINE, 1)
+	}
+}
+
+func testBlockRun() {
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+}
+
+func testSwitch() {
+	for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
+		switch i {
+		case 0:
+			check(LINE, 1)
+		case 1:
+			check(LINE, 1)
+		case 2:
+			check(LINE, 1)
+		default:
+			check(LINE, 2)
+		}
+	}
+}
+
+func testTypeSwitch() {
+	var x = []interface{}{1, 2.0, "hi"}
+	for _, v := range x {
+		switch func() { check(LINE, 3) }(); v.(type) {
+		case int:
+			check(LINE, 1)
+		case float64:
+			check(LINE, 1)
+		case string:
+			check(LINE, 1)
+		case complex128:
+			check(LINE, 0)
+		default:
+			check(LINE, 0)
+		}
+	}
+}
+
+func testSelect1() {
+	c := make(chan int)
+	go func() {
+		for i := 0; i < 1000; i++ {
+			c <- i
+		}
+	}()
+	for {
+		select {
+		case <-c:
+			check(LINE, anything)
+		case <-c:
+			check(LINE, anything)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+func testSelect2() {
+	c1 := make(chan int, 1000)
+	c2 := make(chan int, 1000)
+	for i := 0; i < 1000; i++ {
+		c1 <- i
+		c2 <- i
+	}
+	for {
+		select {
+		case <-c1:
+			check(LINE, 1000)
+		case <-c2:
+			check(LINE, 1000)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+// Empty control statements created syntax errors. This function
+// is here just to be sure that those are handled correctly now.
+func testEmptySwitches() {
+	check(LINE, 1)
+	switch 3 {
+	}
+	check(LINE, 1)
+	switch i := (interface{})(3).(int); i {
+	}
+	check(LINE, 1)
+	c := make(chan int)
+	go func() {
+		check(LINE, 1)
+		c <- 1
+		select {}
+	}()
+	<-c
+	check(LINE, 1)
+}
diff --git a/cmd/digraph/digraph.go b/cmd/digraph/digraph.go
new file mode 100644
index 0000000..3ad2950
--- /dev/null
+++ b/cmd/digraph/digraph.go
@@ -0,0 +1,540 @@
+// The digraph command performs queries over unlabelled directed graphs
+// represented in text form.  It is intended to integrate nicely with
+// typical UNIX command pipelines.
+//
+// Since directed graphs (import graphs, reference graphs, call graphs,
+// etc) often arise during software tool development and debugging, this
+// command is included in the go.tools repository.
+//
+// TODO(adonovan):
+// - support input files other than stdin
+// - suport alternative formats (AT&T GraphViz, CSV, etc),
+//   a comment syntax, etc.
+// - allow queries to nest, like Blaze query language.
+//
+package main // import "golang.org/x/tools/cmd/digraph"
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"os"
+	"sort"
+	"strconv"
+	"unicode"
+	"unicode/utf8"
+)
+
+const Usage = `digraph: queries over directed graphs in text form.
+
+Graph format:
+
+  Each line contains zero or more words.  Words are separated by
+  unquoted whitespace; words may contain Go-style double-quoted portions,
+  allowing spaces and other characters to be expressed.
+
+  Each field declares a node, and if there are more than one,
+  an edge from the first to each subsequent one.
+  The graph is provided on the standard input.
+
+  For instance, the following (acyclic) graph specifies a partial order
+  among the subtasks of getting dressed:
+
+	% cat clothes.txt
+	socks shoes
+	"boxer shorts" pants
+	pants belt shoes
+	shirt tie sweater
+	sweater jacket
+	hat
+
+  The line "shirt tie sweater" indicates the two edges shirt -> tie and
+  shirt -> sweater, not shirt -> tie -> sweater.
+
+Supported queries:
+
+  nodes
+	the set of all nodes
+  degree
+	the in-degree and out-degree of each node.
+  preds <label> ...
+	the set of immediate predecessors of the specified nodes
+  succs <label> ...
+	the set of immediate successors of the specified nodes
+  forward <label> ...
+	the set of nodes transitively reachable from the specified nodes
+  reverse <label> ...
+	the set of nodes that transitively reach the specified nodes
+  somepath <label> <label>
+	the list of nodes on some arbitrary path from the first node to the second
+  allpaths <label> <label>
+	the set of nodes on all paths from the first node to the second
+  sccs
+	all strongly connected components (one per line)
+  scc <label>
+	the set of nodes nodes strongly connected to the specified one
+
+Example usage:
+
+   Show the transitive closure of imports of the digraph tool itself:
+   % go list -f '{{.ImportPath}}{{.Imports}}' ... | tr '[]' '  ' |
+         digraph forward golang.org/x/tools/cmd/digraph
+
+   Show which clothes (see above) must be donned before a jacket:
+   %  digraph reverse jacket <clothes.txt
+
+`
+
+func main() {
+	flag.Parse()
+
+	args := flag.Args()
+	if len(args) == 0 {
+		fmt.Println(Usage)
+		return
+	}
+
+	if err := digraph(args[0], args[1:]); err != nil {
+		fmt.Fprintf(os.Stderr, "digraph: %s\n", err)
+		os.Exit(1)
+	}
+}
+
+type nodelist []string
+
+func (l nodelist) println(sep string) {
+	for i, label := range l {
+		if i > 0 {
+			fmt.Fprint(stdout, sep)
+		}
+		fmt.Fprint(stdout, label)
+	}
+	fmt.Fprintln(stdout)
+}
+
+type nodeset map[string]bool
+
+func (s nodeset) sort() nodelist {
+	labels := make(nodelist, len(s))
+	var i int
+	for label := range s {
+		labels[i] = label
+		i++
+	}
+	sort.Strings(labels)
+	return labels
+}
+
+func (s nodeset) addAll(x nodeset) {
+	for label := range x {
+		s[label] = true
+	}
+}
+
+// A graph maps nodes to the non-nil set of their immediate successors.
+type graph map[string]nodeset
+
+func (g graph) addNode(label string) nodeset {
+	edges := g[label]
+	if edges == nil {
+		edges = make(nodeset)
+		g[label] = edges
+	}
+	return edges
+}
+
+func (g graph) addEdges(from string, to ...string) {
+	edges := g.addNode(from)
+	for _, to := range to {
+		g.addNode(to)
+		edges[to] = true
+	}
+}
+
+func (g graph) reachableFrom(roots nodeset) nodeset {
+	seen := make(nodeset)
+	var visit func(label string)
+	visit = func(label string) {
+		if !seen[label] {
+			seen[label] = true
+			for e := range g[label] {
+				visit(e)
+			}
+		}
+	}
+	for root := range roots {
+		visit(root)
+	}
+	return seen
+}
+
+func (g graph) transpose() graph {
+	rev := make(graph)
+	for label, edges := range g {
+		rev.addNode(label)
+		for succ := range edges {
+			rev.addEdges(succ, label)
+		}
+	}
+	return rev
+}
+
+func (g graph) sccs() []nodeset {
+	// Kosaraju's algorithm---Tarjan is overkill here.
+
+	// Forward pass.
+	S := make(nodelist, 0, len(g)) // postorder stack
+	seen := make(nodeset)
+	var visit func(label string)
+	visit = func(label string) {
+		if !seen[label] {
+			seen[label] = true
+			for e := range g[label] {
+				visit(e)
+			}
+			S = append(S, label)
+		}
+	}
+	for label := range g {
+		visit(label)
+	}
+
+	// Reverse pass.
+	rev := g.transpose()
+	var scc nodeset
+	seen = make(nodeset)
+	var rvisit func(label string)
+	rvisit = func(label string) {
+		if !seen[label] {
+			seen[label] = true
+			scc[label] = true
+			for e := range rev[label] {
+				rvisit(e)
+			}
+		}
+	}
+	var sccs []nodeset
+	for len(S) > 0 {
+		top := S[len(S)-1]
+		S = S[:len(S)-1] // pop
+		if !seen[top] {
+			scc = make(nodeset)
+			rvisit(top)
+			sccs = append(sccs, scc)
+		}
+	}
+	return sccs
+}
+
+func parse(rd io.Reader) (graph, error) {
+	g := make(graph)
+
+	var linenum int
+	in := bufio.NewScanner(rd)
+	for in.Scan() {
+		linenum++
+		// Split into words, honoring double-quotes per Go spec.
+		words, err := split(in.Text())
+		if err != nil {
+			return nil, fmt.Errorf("at line %d: %v", linenum, err)
+		}
+		if len(words) > 0 {
+			g.addEdges(words[0], words[1:]...)
+		}
+	}
+	if err := in.Err(); err != nil {
+		return nil, err
+	}
+	return g, nil
+}
+
+var stdin io.Reader = os.Stdin
+var stdout io.Writer = os.Stdout
+
+func digraph(cmd string, args []string) error {
+	// Parse the input graph.
+	g, err := parse(stdin)
+	if err != nil {
+		return err
+	}
+
+	// Parse the command line.
+	switch cmd {
+	case "nodes":
+		if len(args) != 0 {
+			return fmt.Errorf("usage: digraph nodes")
+		}
+		nodes := make(nodeset)
+		for label := range g {
+			nodes[label] = true
+		}
+		nodes.sort().println("\n")
+
+	case "degree":
+		if len(args) != 0 {
+			return fmt.Errorf("usage: digraph degree")
+		}
+		nodes := make(nodeset)
+		for label := range g {
+			nodes[label] = true
+		}
+		rev := g.transpose()
+		for _, label := range nodes.sort() {
+			fmt.Fprintf(stdout, "%d\t%d\t%s\n", len(rev[label]), len(g[label]), label)
+		}
+
+	case "succs", "preds":
+		if len(args) == 0 {
+			return fmt.Errorf("usage: digraph %s <label> ...", cmd)
+		}
+		g := g
+		if cmd == "preds" {
+			g = g.transpose()
+		}
+		result := make(nodeset)
+		for _, root := range args {
+			edges := g[root]
+			if edges == nil {
+				return fmt.Errorf("no such node %q", root)
+			}
+			result.addAll(edges)
+		}
+		result.sort().println("\n")
+
+	case "forward", "reverse":
+		if len(args) == 0 {
+			return fmt.Errorf("usage: digraph %s <label> ...", cmd)
+		}
+		roots := make(nodeset)
+		for _, root := range args {
+			if g[root] == nil {
+				return fmt.Errorf("no such node %q", root)
+			}
+			roots[root] = true
+		}
+		g := g
+		if cmd == "reverse" {
+			g = g.transpose()
+		}
+		g.reachableFrom(roots).sort().println("\n")
+
+	case "somepath":
+		if len(args) != 2 {
+			return fmt.Errorf("usage: digraph somepath <from> <to>")
+		}
+		from, to := args[0], args[1]
+		if g[from] == nil {
+			return fmt.Errorf("no such 'from' node %q", from)
+		}
+		if g[to] == nil {
+			return fmt.Errorf("no such 'to' node %q", to)
+		}
+
+		seen := make(nodeset)
+		var visit func(path nodelist, label string) bool
+		visit = func(path nodelist, label string) bool {
+			if !seen[label] {
+				seen[label] = true
+				if label == to {
+					append(path, label).println("\n")
+					return true // unwind
+				}
+				for e := range g[label] {
+					if visit(append(path, label), e) {
+						return true
+					}
+				}
+			}
+			return false
+		}
+		if !visit(make(nodelist, 0, 100), from) {
+			return fmt.Errorf("no path from %q to %q", args[0], args[1])
+		}
+
+	case "allpaths":
+		if len(args) != 2 {
+			return fmt.Errorf("usage: digraph allpaths <from> <to>")
+		}
+		from, to := args[0], args[1]
+		if g[from] == nil {
+			return fmt.Errorf("no such 'from' node %q", from)
+		}
+		if g[to] == nil {
+			return fmt.Errorf("no such 'to' node %q", to)
+		}
+
+		seen := make(nodeset) // value of seen[x] indicates whether x is on some path to 'to'
+		var visit func(label string) bool
+		visit = func(label string) bool {
+			reachesTo, ok := seen[label]
+			if !ok {
+				reachesTo = label == to
+
+				seen[label] = reachesTo
+				for e := range g[label] {
+					if visit(e) {
+						reachesTo = true
+					}
+				}
+				seen[label] = reachesTo
+			}
+			return reachesTo
+		}
+		if !visit(from) {
+			return fmt.Errorf("no path from %q to %q", from, to)
+		}
+		for label, reachesTo := range seen {
+			if !reachesTo {
+				delete(seen, label)
+			}
+		}
+		seen.sort().println("\n")
+
+	case "sccs":
+		if len(args) != 0 {
+			return fmt.Errorf("usage: digraph sccs")
+		}
+		for _, scc := range g.sccs() {
+			scc.sort().println(" ")
+		}
+
+	case "scc":
+		if len(args) != 1 {
+			return fmt.Errorf("usage: digraph scc <label>")
+		}
+		label := args[0]
+		if g[label] == nil {
+			return fmt.Errorf("no such node %q", label)
+		}
+		for _, scc := range g.sccs() {
+			if scc[label] {
+				scc.sort().println("\n")
+				break
+			}
+		}
+
+	default:
+		return fmt.Errorf("no such command %q", cmd)
+	}
+
+	return nil
+}
+
+// -- Utilities --------------------------------------------------------
+
+// split splits a line into words, which are generally separated by
+// spaces, but Go-style double-quoted string literals are also supported.
+// (This approximates the behaviour of the Bourne shell.)
+//
+//   `one "two three"` -> ["one" "two three"]
+//   `a"\n"b` -> ["a\nb"]
+//
+func split(line string) ([]string, error) {
+	var (
+		words   []string
+		inWord  bool
+		current bytes.Buffer
+	)
+
+	for len(line) > 0 {
+		r, size := utf8.DecodeRuneInString(line)
+		if unicode.IsSpace(r) {
+			if inWord {
+				words = append(words, current.String())
+				current.Reset()
+				inWord = false
+			}
+		} else if r == '"' {
+			var ok bool
+			size, ok = quotedLength(line)
+			if !ok {
+				return nil, errors.New("invalid quotation")
+			}
+			s, err := strconv.Unquote(line[:size])
+			if err != nil {
+				return nil, err
+			}
+			current.WriteString(s)
+			inWord = true
+		} else {
+			current.WriteRune(r)
+			inWord = true
+		}
+		line = line[size:]
+	}
+	if inWord {
+		words = append(words, current.String())
+	}
+	return words, nil
+}
+
+// quotedLength returns the length in bytes of the prefix of input that
+// contain a possibly-valid double-quoted Go string literal.
+//
+// On success, n is at least two (""); input[:n] may be passed to
+// strconv.Unquote to interpret its value, and input[n:] contains the
+// rest of the input.
+//
+// On failure, quotedLength returns false, and the entire input can be
+// passed to strconv.Unquote if an informative error message is desired.
+//
+// quotedLength does not and need not detect all errors, such as
+// invalid hex or octal escape sequences, since it assumes
+// strconv.Unquote will be applied to the prefix.  It guarantees only
+// that if there is a prefix of input containing a valid string literal,
+// its length is returned.
+//
+// TODO(adonovan): move this into a strconv-like utility package.
+//
+func quotedLength(input string) (n int, ok bool) {
+	var offset int
+
+	// next returns the rune at offset, or -1 on EOF.
+	// offset advances to just after that rune.
+	next := func() rune {
+		if offset < len(input) {
+			r, size := utf8.DecodeRuneInString(input[offset:])
+			offset += size
+			return r
+		}
+		return -1
+	}
+
+	if next() != '"' {
+		return // error: not a quotation
+	}
+
+	for {
+		r := next()
+		if r == '\n' || r < 0 {
+			return // error: string literal not terminated
+		}
+		if r == '"' {
+			return offset, true // success
+		}
+		if r == '\\' {
+			var skip int
+			switch next() {
+			case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"':
+				skip = 0
+			case '0', '1', '2', '3', '4', '5', '6', '7':
+				skip = 2
+			case 'x':
+				skip = 2
+			case 'u':
+				skip = 4
+			case 'U':
+				skip = 8
+			default:
+				return // error: invalid escape
+			}
+
+			for i := 0; i < skip; i++ {
+				next()
+			}
+		}
+	}
+}
diff --git a/cmd/digraph/digraph_test.go b/cmd/digraph/digraph_test.go
new file mode 100644
index 0000000..0c90304
--- /dev/null
+++ b/cmd/digraph/digraph_test.go
@@ -0,0 +1,121 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestDigraph(t *testing.T) {
+	const g1 = `
+socks shoes
+shorts pants
+pants belt shoes
+shirt tie sweater
+sweater jacket
+hat
+`
+
+	const g2 = `
+a b c
+b d
+c d
+d c
+`
+
+	for _, test := range []struct {
+		input string
+		cmd   string
+		args  []string
+		want  string
+	}{
+		{g1, "nodes", nil, "belt\nhat\njacket\npants\nshirt\nshoes\nshorts\nsocks\nsweater\ntie\n"},
+		{g1, "reverse", []string{"jacket"}, "jacket\nshirt\nsweater\n"},
+		{g1, "forward", []string{"socks"}, "shoes\nsocks\n"},
+		{g1, "forward", []string{"socks", "sweater"}, "jacket\nshoes\nsocks\nsweater\n"},
+
+		{g2, "allpaths", []string{"a", "d"}, "a\nb\nc\nd\n"},
+
+		{g2, "sccs", nil, "a\nb\nc d\n"},
+		{g2, "scc", []string{"d"}, "c\nd\n"},
+		{g2, "succs", []string{"a"}, "b\nc\n"},
+		{g2, "preds", []string{"c"}, "a\nd\n"},
+		{g2, "preds", []string{"c", "d"}, "a\nb\nc\nd\n"},
+	} {
+		stdin = strings.NewReader(test.input)
+		stdout = new(bytes.Buffer)
+		if err := digraph(test.cmd, test.args); err != nil {
+			t.Error(err)
+			continue
+		}
+
+		got := stdout.(fmt.Stringer).String()
+		if got != test.want {
+			t.Errorf("digraph(%s, %s) = %q, want %q", test.cmd, test.args, got, test.want)
+		}
+	}
+
+	// TODO(adonovan):
+	// - test somepath (it's nondeterministic).
+	// - test errors
+}
+
+func TestSplit(t *testing.T) {
+	for _, test := range []struct {
+		line string
+		want []string
+	}{
+		{`one "2a 2b" three`, []string{"one", "2a 2b", "three"}},
+		{`one tw"\n\x0a\u000a\012"o three`, []string{"one", "tw\n\n\n\no", "three"}},
+	} {
+		got, err := split(test.line)
+		if err != nil {
+			t.Errorf("split(%s) failed: %v", test.line, err)
+		}
+		if !reflect.DeepEqual(got, test.want) {
+			t.Errorf("split(%s) = %v, want %v", test.line, got, test.want)
+		}
+	}
+}
+
+func TestQuotedLength(t *testing.T) {
+	for _, test := range []struct {
+		input string
+		want  int
+	}{
+		{`"abc"`, 5},
+		{`"abc"def`, 5},
+		{`"abc\"d"ef`, 8}, // "abc\"d" is consumed, ef is residue
+		{`"\012\n\x0a\u000a\U0000000a"`, 28},
+		{"\"\xff\"", 3}, // bad UTF-8 is ok
+		{`"\xff"`, 6},   // hex escape for bad UTF-8 is ok
+	} {
+		got, ok := quotedLength(test.input)
+		if !ok {
+			got = 0
+		}
+		if got != test.want {
+			t.Errorf("quotedLength(%s) = %d, want %d", test.input, got, test.want)
+		}
+	}
+
+	// errors
+	for _, input := range []string{
+		``,            // not a quotation
+		`a`,           // not a quotation
+		`'a'`,         // not a quotation
+		`"a`,          // not terminated
+		`"\0"`,        // short octal escape
+		`"\x1"`,       // short hex escape
+		`"\u000"`,     // short \u escape
+		`"\U0000000"`, // short \U escape
+		`"\k"`,        // invalid escape
+		"\"ab\nc\"",   // newline
+	} {
+		if n, ok := quotedLength(input); ok {
+			t.Errorf("quotedLength(%s) = %d, want !ok", input, n)
+		}
+	}
+}
diff --git a/cmd/eg/eg.go b/cmd/eg/eg.go
new file mode 100644
index 0000000..5970c1a
--- /dev/null
+++ b/cmd/eg/eg.go
@@ -0,0 +1,150 @@
+// The eg command performs example-based refactoring.
+// For documentation, run the command, or see Help in
+// golang.org/x/tools/refactor/eg.
+package main // import "golang.org/x/tools/cmd/eg"
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"os"
+	"os/exec"
+	"strings"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/go/loader"
+	"golang.org/x/tools/refactor/eg"
+)
+
+var (
+	beforeeditFlag = flag.String("beforeedit", "", "A command to exec before each file is edited (e.g. chmod, checkout).  Whitespace delimits argument words.  The string '{}' is replaced by the file name.")
+	helpFlag       = flag.Bool("help", false, "show detailed help message")
+	templateFlag   = flag.String("t", "", "template.go file specifying the refactoring")
+	transitiveFlag = flag.Bool("transitive", false, "apply refactoring to all dependencies too")
+	writeFlag      = flag.Bool("w", false, "rewrite input files in place (by default, the results are printed to standard output)")
+	verboseFlag    = flag.Bool("v", false, "show verbose matcher diagnostics")
+)
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const usage = `eg: an example-based refactoring tool.
+
+Usage: eg -t template.go [-w] [-transitive] <args>...
+
+-help            show detailed help message
+-t template.go	 specifies the template file (use -help to see explanation)
+-w          	 causes files to be re-written in place.
+-transitive 	 causes all dependencies to be refactored too.
+-v               show verbose matcher diagnostics
+-beforeedit cmd  a command to exec before each file is modified.
+                 "{}" represents the name of the file.
+` + loader.FromArgsUsage
+
+func main() {
+	if err := doMain(); err != nil {
+		fmt.Fprintf(os.Stderr, "eg: %s\n", err)
+		os.Exit(1)
+	}
+}
+
+func doMain() error {
+	flag.Parse()
+	args := flag.Args()
+
+	if *helpFlag {
+		fmt.Fprint(os.Stderr, eg.Help)
+		os.Exit(2)
+	}
+
+	if len(args) == 0 {
+		fmt.Fprint(os.Stderr, usage)
+		os.Exit(1)
+	}
+
+	if *templateFlag == "" {
+		return fmt.Errorf("no -t template.go file specified")
+	}
+
+	conf := loader.Config{
+		Fset:       token.NewFileSet(),
+		ParserMode: parser.ParseComments,
+	}
+
+	// The first Created package is the template.
+	conf.CreateFromFilenames("template", *templateFlag)
+
+	if _, err := conf.FromArgs(args, true); err != nil {
+		return err
+	}
+
+	// Load, parse and type-check the whole program.
+	iprog, err := conf.Load()
+	if err != nil {
+		return err
+	}
+
+	// Analyze the template.
+	template := iprog.Created[0]
+	xform, err := eg.NewTransformer(iprog.Fset, template, *verboseFlag)
+	if err != nil {
+		return err
+	}
+
+	// Apply it to the input packages.
+	var pkgs []*loader.PackageInfo
+	if *transitiveFlag {
+		for _, info := range iprog.AllPackages {
+			pkgs = append(pkgs, info)
+		}
+	} else {
+		pkgs = iprog.InitialPackages()
+	}
+	var hadErrors bool
+	for _, pkg := range pkgs {
+		if pkg == template {
+			continue
+		}
+		for _, file := range pkg.Files {
+			n := xform.Transform(&pkg.Info, pkg.Pkg, file)
+			if n == 0 {
+				continue
+			}
+			filename := iprog.Fset.File(file.Pos()).Name()
+			fmt.Fprintf(os.Stderr, "=== %s (%d matches)\n", filename, n)
+			if *writeFlag {
+				// Run the before-edit command (e.g. "chmod +w",  "checkout") if any.
+				if *beforeeditFlag != "" {
+					args := strings.Fields(*beforeeditFlag)
+					// Replace "{}" with the filename, like find(1).
+					for i := range args {
+						if i > 0 {
+							args[i] = strings.Replace(args[i], "{}", filename, -1)
+						}
+					}
+					cmd := exec.Command(args[0], args[1:]...)
+					cmd.Stdout = os.Stdout
+					cmd.Stderr = os.Stderr
+					if err := cmd.Run(); err != nil {
+						fmt.Fprintf(os.Stderr, "Warning: edit hook %q failed (%s)\n",
+							args, err)
+					}
+				}
+				if err := eg.WriteAST(iprog.Fset, filename, file); err != nil {
+					fmt.Fprintf(os.Stderr, "eg: %s\n", err)
+					hadErrors = true
+				}
+			} else {
+				printer.Fprint(os.Stdout, iprog.Fset, file)
+			}
+		}
+	}
+	if hadErrors {
+		os.Exit(1)
+	}
+	return nil
+}
diff --git a/cmd/fiximports/main.go b/cmd/fiximports/main.go
new file mode 100644
index 0000000..86ae777
--- /dev/null
+++ b/cmd/fiximports/main.go
@@ -0,0 +1,451 @@
+// Copyright 2015 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 fiximports command fixes import declarations to use the canonical
+// import path for packages that have an "import comment" as defined by
+// https://golang.org/s/go14customimport.
+//
+//
+// Background
+//
+// The Go 1 custom import path mechanism lets the maintainer of a
+// package give it a stable name by which clients may import and "go
+// get" it, independent of the underlying version control system (such
+// as Git) or server (such as github.com) that hosts it.  Requests for
+// the custom name are redirected to the underlying name.  This allows
+// packages to be migrated from one underlying server or system to
+// another without breaking existing clients.
+//
+// Because this redirect mechanism creates aliases for existing
+// packages, it's possible for a single program to import the same
+// package by its canonical name and by an alias.  The resulting
+// executable will contain two copies of the package, which is wasteful
+// at best and incorrect at worst.
+//
+// To avoid this, "go build" reports an error if it encounters a special
+// comment like the one below, and if the import path in the comment
+// does not match the path of the enclosing package relative to
+// GOPATH/src:
+//
+//      $ grep ^package $GOPATH/src/github.com/bob/vanity/foo/foo.go
+// 	package foo // import "vanity.com/foo"
+//
+// The error from "go build" indicates that the package canonically
+// known as "vanity.com/foo" is locally installed under the
+// non-canonical name "github.com/bob/vanity/foo".
+//
+//
+// Usage
+//
+// When a package that you depend on introduces a custom import comment,
+// and your workspace imports it by the non-canonical name, your build
+// will stop working as soon as you update your copy of that package
+// using "go get -u".
+//
+// The purpose of the fiximports tool is to fix up all imports of the
+// non-canonical path within a Go workspace, replacing them with imports
+// of the canonical path.  Following a run of fiximports, the workspace
+// will no longer depend on the non-canonical copy of the package, so it
+// should be safe to delete.  It may be necessary to run "go get -u"
+// again to ensure that the package is locally installed under its
+// canonical path, if it was not already.
+//
+// The fiximports tool operates locally; it does not make HTTP requests
+// and does not discover new custom import comments.  It only operates
+// on non-canonical packages present in your workspace.
+//
+// The -baddomains flag is a list of domain names that should always be
+// considered non-canonical.  You can use this if you wish to make sure
+// that you no longer have any dependencies on packages from that
+// domain, even those that do not yet provide a canical import path
+// comment.  For example, the default value of -baddomains includes the
+// moribund code hosting site code.google.com, so fiximports will report
+// an error for each import of a package from this domain remaining
+// after canonicalization.
+//
+// To see the changes fiximports would make without applying them, use
+// the -n flag.
+//
+package main
+
+import (
+	"bytes"
+	"encoding/json"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// flags
+var (
+	dryrun     = flag.Bool("n", false, "dry run: show changes, but don't apply them")
+	badDomains = flag.String("baddomains", "code.google.com",
+		"a comma-separated list of domains from which packages should not be imported")
+)
+
+// seams for testing
+var (
+	stderr    io.Writer = os.Stderr
+	writeFile           = ioutil.WriteFile
+)
+
+const usage = `fiximports: rewrite import paths to use canonical package names.
+
+Usage: fiximports [-n] package...
+
+The package... arguments specify a list of packages
+in the style of the go tool; see "go help packages".
+Hint: use "all" or "..." to match the entire workspace.
+
+For details, see http://godoc.org/golang.org/x/tools/cmd/fiximports.
+
+Flags:
+  -n:	       dry run: show changes, but don't apply them
+  -baddomains  a comma-separated list of domains from which packages
+               should not be imported
+`
+
+func main() {
+	flag.Parse()
+
+	if len(flag.Args()) == 0 {
+		fmt.Fprintf(stderr, usage)
+		os.Exit(1)
+	}
+	if !fiximports(flag.Args()...) {
+		os.Exit(1)
+	}
+}
+
+// fiximports fixes imports in the specified packages.
+// Invariant: a false result implies an error was already printed.
+func fiximports(packages ...string) bool {
+	// importedBy is the transpose of the package import graph.
+	importedBy := make(map[string]map[*build.Package]bool)
+
+	// addEdge adds an edge to the import graph.
+	addEdge := func(from *build.Package, to string) {
+		if to == "C" || to == "unsafe" {
+			return // fake
+		}
+		pkgs := importedBy[to]
+		if pkgs == nil {
+			pkgs = make(map[*build.Package]bool)
+			importedBy[to] = pkgs
+		}
+		pkgs[from] = true
+	}
+
+	// List metadata for all packages in the workspace.
+	pkgs, err := list("...")
+	if err != nil {
+		fmt.Fprintf(stderr, "importfix: %v\n", err)
+		return false
+	}
+
+	// noncanonical maps each non-canonical package path to
+	// its canonical name.
+	// A present nil value indicates that the canonical package
+	// is unknown: hosted on a bad domain with no redirect.
+	noncanonical := make(map[string]*build.Package)
+	domains := strings.Split(*badDomains, ",")
+
+	// Find non-canonical packages and populate importedBy graph.
+	for _, p := range pkgs {
+		if p.Error != nil {
+			msg := p.Error.Err
+			if strings.Contains(msg, "code in directory") &&
+				strings.Contains(msg, "expects import") {
+				// don't show the very errors we're trying to fix
+			} else {
+				fmt.Fprintln(stderr, msg)
+			}
+		}
+
+		for _, imp := range p.Imports {
+			addEdge(&p.Package, imp)
+		}
+		for _, imp := range p.TestImports {
+			addEdge(&p.Package, imp)
+		}
+		for _, imp := range p.XTestImports {
+			addEdge(&p.Package, imp)
+		}
+
+		if p.ImportComment != "" {
+			if p.ImportComment != p.ImportPath {
+				noncanonical[p.ImportPath] = &p.Package
+			}
+		} else {
+			for _, domain := range domains {
+				slash := strings.Index(p.ImportPath, "/")
+				if slash < 0 {
+					continue // no slash: standard package
+				}
+				if p.ImportPath[:slash] == domain {
+					// Package comes from bad domain and has no import comment.
+					// Report an error each time this package is imported.
+					noncanonical[p.ImportPath] = nil
+
+					// TODO(adonovan): should we make an HTTP request to
+					// see if there's an HTTP redirect, a "go-import" meta tag,
+					// or an import comment in the the latest revision?
+					// It would duplicate a lot of logic from "go get".
+				}
+				break
+			}
+		}
+	}
+
+	// Find all clients (direct importers) of noncanonical packages.
+	// These are the packages that need fixing up.
+	clients := make(map[*build.Package]bool)
+	for path := range noncanonical {
+		for client := range importedBy[path] {
+			clients[client] = true
+		}
+	}
+
+	// Restrict rewrites to the set of packages specified by the user.
+	if len(packages) == 1 && (packages[0] == "all" || packages[0] == "...") {
+		// no restriction
+	} else {
+		pkgs, err := list(packages...)
+		if err != nil {
+			fmt.Fprintf(stderr, "importfix: %v\n", err)
+			return false
+		}
+		seen := make(map[string]bool)
+		for _, p := range pkgs {
+			seen[p.ImportPath] = true
+		}
+		for client := range clients {
+			if !seen[client.ImportPath] {
+				delete(clients, client)
+			}
+		}
+	}
+
+	// Rewrite selected client packages.
+	ok := true
+	for client := range clients {
+		if !rewritePackage(client, noncanonical) {
+			ok = false
+
+			// There were errors.
+			// Show direct and indirect imports of client.
+			seen := make(map[string]bool)
+			var direct, indirect []string
+			for p := range importedBy[client.ImportPath] {
+				direct = append(direct, p.ImportPath)
+				seen[p.ImportPath] = true
+			}
+
+			var visit func(path string)
+			visit = func(path string) {
+				for q := range importedBy[path] {
+					qpath := q.ImportPath
+					if !seen[qpath] {
+						seen[qpath] = true
+						indirect = append(indirect, qpath)
+						visit(qpath)
+					}
+				}
+			}
+
+			if direct != nil {
+				fmt.Fprintf(stderr, "\timported directly by:\n")
+				sort.Strings(direct)
+				for _, path := range direct {
+					fmt.Fprintf(stderr, "\t\t%s\n", path)
+					visit(path)
+				}
+
+				if indirect != nil {
+					fmt.Fprintf(stderr, "\timported indirectly by:\n")
+					sort.Strings(indirect)
+					for _, path := range indirect {
+						fmt.Fprintf(stderr, "\t\t%s\n", path)
+					}
+				}
+			}
+		}
+	}
+
+	return ok
+}
+
+// Invariant: false result => error already printed.
+func rewritePackage(client *build.Package, noncanonical map[string]*build.Package) bool {
+	ok := true
+
+	used := make(map[string]bool)
+	var filenames []string
+	filenames = append(filenames, client.GoFiles...)
+	filenames = append(filenames, client.TestGoFiles...)
+	filenames = append(filenames, client.XTestGoFiles...)
+	var first bool
+	for _, filename := range filenames {
+		if !first {
+			first = true
+			fmt.Fprintf(stderr, "%s\n", client.ImportPath)
+		}
+		err := rewriteFile(filepath.Join(client.Dir, filename), noncanonical, used)
+		if err != nil {
+			fmt.Fprintf(stderr, "\tERROR: %v\n", err)
+			ok = false
+		}
+	}
+
+	// Show which imports were renamed in this package.
+	var keys []string
+	for key := range used {
+		keys = append(keys, key)
+	}
+	sort.Strings(keys)
+	for _, key := range keys {
+		if p := noncanonical[key]; p != nil {
+			fmt.Fprintf(stderr, "\tfixed: %s -> %s\n", key, p.ImportComment)
+		} else {
+			fmt.Fprintf(stderr, "\tERROR: %s has no import comment\n", key)
+			ok = false
+		}
+	}
+
+	return ok
+}
+
+// rewrite reads, modifies, and writes filename, replacing all imports
+// of packages P in noncanonical by noncanonical[P].
+// It records in used which noncanonical packages were imported.
+// used[P]=="" indicates that P was imported but its canonical path is unknown.
+func rewriteFile(filename string, noncanonical map[string]*build.Package, used map[string]bool) error {
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
+	if err != nil {
+		return err
+	}
+	var changed bool
+	for _, imp := range f.Imports {
+		impPath, err := strconv.Unquote(imp.Path.Value)
+		if err != nil {
+			log.Printf("%s: bad import spec %q: %v",
+				fset.Position(imp.Pos()), imp.Path.Value, err)
+			continue
+		}
+		p, ok := noncanonical[impPath]
+		if !ok {
+			continue // import path is canonical
+		}
+
+		used[impPath] = true
+
+		if p == nil {
+			// The canonical path is unknown.
+			// Show the offending import.
+			// TODO(adonovan): should we show the actual source text?
+			fmt.Fprintf(stderr, "\t%s:%d: import %q\n",
+				shortPath(filename),
+				fset.Position(imp.Pos()).Line, impPath)
+			continue
+		}
+
+		changed = true
+
+		imp.Path.Value = strconv.Quote(p.ImportComment)
+
+		// Add a renaming import if necessary.
+		//
+		// This is a guess at best.  We can't see whether a 'go
+		// get' of the canonical import path would have the same
+		// name or not.  Assume it's the last segment.
+		//
+		// TODO(adonovan): should we make an HTTP request?
+		newBase := path.Base(p.ImportComment)
+		if imp.Name == nil && newBase != p.Name {
+			imp.Name = &ast.Ident{Name: p.Name}
+		}
+	}
+
+	if changed && !*dryrun {
+		var buf bytes.Buffer
+		if err := format.Node(&buf, fset, f); err != nil {
+			return fmt.Errorf("%s: couldn't format file: %v", filename, err)
+		}
+		return writeFile(filename, buf.Bytes(), 0644)
+	}
+
+	return nil
+}
+
+// listPackage is a copy of cmd/go/list.Package.
+// It has more fields than build.Package and we need some of them.
+type listPackage struct {
+	build.Package
+	Error *packageError // error loading package
+}
+
+// A packageError describes an error loading information about a package.
+type packageError struct {
+	ImportStack []string // shortest path from package named on command line to this one
+	Pos         string   // position of error
+	Err         string   // the error itself
+}
+
+// list runs 'go list' with the specified arguments and returns the
+// metadata for matching packages.
+func list(args ...string) ([]*listPackage, error) {
+	cmd := exec.Command("go", append([]string{"list", "-e", "-json"}, args...)...)
+	cmd.Stdout = new(bytes.Buffer)
+	cmd.Stderr = stderr
+	if err := cmd.Run(); err != nil {
+		return nil, err
+	}
+
+	dec := json.NewDecoder(cmd.Stdout.(io.Reader))
+	var pkgs []*listPackage
+	for {
+		var p listPackage
+		if err := dec.Decode(&p); err == io.EOF {
+			break
+		} else if err != nil {
+			return nil, err
+		}
+		pkgs = append(pkgs, &p)
+	}
+	return pkgs, nil
+}
+
+var cwd string
+
+func init() {
+	var err error
+	cwd, err = os.Getwd()
+	if err != nil {
+		log.Fatalf("os.Getwd: %v", err)
+	}
+}
+
+// shortPath returns an absolute or relative name for path, whatever is shorter.
+// Plundered from $GOROOT/src/cmd/go/build.go.
+func shortPath(path string) string {
+	if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
+		return rel
+	}
+	return path
+}
diff --git a/cmd/fiximports/main_test.go b/cmd/fiximports/main_test.go
new file mode 100644
index 0000000..c8f7bc3
--- /dev/null
+++ b/cmd/fiximports/main_test.go
@@ -0,0 +1,169 @@
+// Copyright 2015 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.
+
+// No testdata on Android.
+
+// +build !android
+
+package main
+
+import (
+	"bytes"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+)
+
+// TODO(adonovan):
+// - test introduction of renaming imports.
+// - test induced failures of rewriteFile.
+
+// Guide to the test packages:
+//
+// new.com/one		-- canonical name for old.com/one
+// old.com/one		-- non-canonical; has import comment "new.com/one"
+// old.com/bad		-- has a parse error
+// fruit.io/orange	\
+// fruit.io/banana	 } orange -> pear -> banana -> titanic.biz/bar
+// fruit.io/pear	/
+// titanic.biz/bar	-- domain is sinking; package has jumped ship to new.com/bar
+// titanic.biz/foo	-- domain is sinking but package has no import comment yet
+
+func TestFixImports(t *testing.T) {
+	gopath := filepath.Join(cwd, "testdata")
+	if err := os.Setenv("GOPATH", gopath); err != nil {
+		t.Fatalf("os.Setenv: %v", err)
+	}
+	defer func() {
+		stderr = os.Stderr
+		*badDomains = "code.google.com"
+	}()
+
+	for i, test := range []struct {
+		packages    []string // packages to rewrite, "go list" syntax
+		badDomains  string   // -baddomains flag
+		wantOK      bool
+		wantStderr  string
+		wantRewrite map[string]string
+	}{
+		// #0. No errors.
+		{
+			packages:   []string{"all"},
+			badDomains: "code.google.com",
+			wantOK:     true,
+			wantStderr: `
+testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
+fruit.io/banana
+	fixed: old.com/one -> new.com/one
+	fixed: titanic.biz/bar -> new.com/bar
+`,
+			wantRewrite: map[string]string{
+				"$GOPATH/src/fruit.io/banana/banana.go": `package banana
+
+import (
+	_ "new.com/bar"
+	_ "new.com/one"
+	_ "titanic.biz/foo"
+)`,
+			},
+		},
+		// #1. No packages needed rewriting.
+		{
+			packages:   []string{"titanic.biz/...", "old.com/...", "new.com/..."},
+			badDomains: "code.google.com",
+			wantOK:     true,
+			wantStderr: `
+testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
+`,
+		},
+		// #2. Some packages without import comments matched bad domains.
+		{
+			packages:   []string{"all"},
+			badDomains: "titanic.biz",
+			wantOK:     false,
+			wantStderr: `
+testdata/src/old.com/bad/bad.go:2:43: expected 'package', found 'EOF'
+fruit.io/banana
+	testdata/src/fruit.io/banana/banana.go:6: import "titanic.biz/foo"
+	fixed: old.com/one -> new.com/one
+	fixed: titanic.biz/bar -> new.com/bar
+	ERROR: titanic.biz/foo has no import comment
+	imported directly by:
+		fruit.io/pear
+	imported indirectly by:
+		fruit.io/orange
+`,
+			wantRewrite: map[string]string{
+				"$GOPATH/src/fruit.io/banana/banana.go": `package banana
+
+import (
+	_ "new.com/bar"
+	_ "new.com/one"
+	_ "titanic.biz/foo"
+)`,
+			},
+		},
+	} {
+		*badDomains = test.badDomains
+
+		stderr = new(bytes.Buffer)
+		gotRewrite := make(map[string]string)
+		writeFile = func(filename string, content []byte, mode os.FileMode) error {
+			filename = strings.Replace(filename, gopath, "$GOPATH", 1)
+			filename = filepath.ToSlash(filename)
+			gotRewrite[filename] = string(bytes.TrimSpace(content))
+			return nil
+		}
+
+		if runtime.GOOS == "windows" {
+			test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/old.com/bad/bad.go`, `testdata\src\old.com\bad\bad.go`, -1)
+			test.wantStderr = strings.Replace(test.wantStderr, `testdata/src/fruit.io/banana/banana.go`, `testdata\src\fruit.io\banana\banana.go`, -1)
+		}
+
+		// Check status code.
+		if fiximports(test.packages...) != test.wantOK {
+			t.Errorf("#%d. fiximports() = %t", i, !test.wantOK)
+		}
+
+		// Compare stderr output.
+		if stderr.(*bytes.Buffer).String() != test.wantStderr {
+			t.Errorf("#%d. stderr: got <<%s>>, want <<%s>>",
+				i, stderr, test.wantStderr)
+		}
+
+		// Compare rewrites.
+		for k, v := range gotRewrite {
+			if test.wantRewrite[k] != v {
+				t.Errorf("#%d. rewrite[%s] = <<%s>>, want <<%s>>",
+					i, k, v, test.wantRewrite[k])
+			}
+			delete(test.wantRewrite, k)
+		}
+		for k, v := range test.wantRewrite {
+			t.Errorf("#%d. rewrite[%s] missing, want <<%s>>", i, k, v)
+		}
+	}
+}
+
+// TestDryRun tests that the -n flag suppresses calls to writeFile.
+func TestDryRun(t *testing.T) {
+	gopath := filepath.Join(cwd, "testdata")
+	if err := os.Setenv("GOPATH", gopath); err != nil {
+		t.Fatalf("os.Setenv: %v", err)
+	}
+
+	*dryrun = true
+	defer func() { *dryrun = false }() // restore
+	stderr = new(bytes.Buffer)
+	writeFile = func(filename string, content []byte, mode os.FileMode) error {
+		t.Fatalf("writeFile(%s) called in dryrun mode", filename)
+		return nil
+	}
+
+	if !fiximports("all") {
+		t.Fatalf("fiximports failed: %s", stderr)
+	}
+}
diff --git a/cmd/fiximports/testdata/src/fruit.io/banana/banana.go b/cmd/fiximports/testdata/src/fruit.io/banana/banana.go
new file mode 100644
index 0000000..04e0242
--- /dev/null
+++ b/cmd/fiximports/testdata/src/fruit.io/banana/banana.go
@@ -0,0 +1,7 @@
+package banana
+
+import (
+	_ "old.com/one"
+	_ "titanic.biz/bar"
+	_ "titanic.biz/foo"
+)
diff --git a/cmd/fiximports/testdata/src/fruit.io/orange/orange.go b/cmd/fiximports/testdata/src/fruit.io/orange/orange.go
new file mode 100644
index 0000000..ae65daa
--- /dev/null
+++ b/cmd/fiximports/testdata/src/fruit.io/orange/orange.go
@@ -0,0 +1,3 @@
+package orange
+
+import _ "fruit.io/pear"
diff --git a/cmd/fiximports/testdata/src/fruit.io/pear/pear.go b/cmd/fiximports/testdata/src/fruit.io/pear/pear.go
new file mode 100644
index 0000000..de92df0
--- /dev/null
+++ b/cmd/fiximports/testdata/src/fruit.io/pear/pear.go
@@ -0,0 +1,3 @@
+package pear
+
+import _ "fruit.io/banana"
diff --git a/cmd/fiximports/testdata/src/new.com/one/one.go b/cmd/fiximports/testdata/src/new.com/one/one.go
new file mode 100644
index 0000000..a8c5e83
--- /dev/null
+++ b/cmd/fiximports/testdata/src/new.com/one/one.go
@@ -0,0 +1 @@
+package one // import "new.com/one"
diff --git a/cmd/fiximports/testdata/src/old.com/bad/bad.go b/cmd/fiximports/testdata/src/old.com/bad/bad.go
new file mode 100644
index 0000000..a1a3d1a
--- /dev/null
+++ b/cmd/fiximports/testdata/src/old.com/bad/bad.go
@@ -0,0 +1,2 @@
+// This ill-formed Go source file is here to ensure the tool is robust
+// against bad packages in the workspace.
diff --git a/cmd/fiximports/testdata/src/old.com/one/one.go b/cmd/fiximports/testdata/src/old.com/one/one.go
new file mode 100644
index 0000000..a8c5e83
--- /dev/null
+++ b/cmd/fiximports/testdata/src/old.com/one/one.go
@@ -0,0 +1 @@
+package one // import "new.com/one"
diff --git a/cmd/fiximports/testdata/src/titanic.biz/bar/bar.go b/cmd/fiximports/testdata/src/titanic.biz/bar/bar.go
new file mode 100644
index 0000000..cc720bc
--- /dev/null
+++ b/cmd/fiximports/testdata/src/titanic.biz/bar/bar.go
@@ -0,0 +1,2 @@
+// This package is moving to new.com too.
+package bar // import "new.com/bar"
diff --git a/cmd/fiximports/testdata/src/titanic.biz/foo/foo.go b/cmd/fiximports/testdata/src/titanic.biz/foo/foo.go
new file mode 100644
index 0000000..145c31b
--- /dev/null
+++ b/cmd/fiximports/testdata/src/titanic.biz/foo/foo.go
@@ -0,0 +1,2 @@
+// This package hasn't jumped ship yet.
+package foo
diff --git a/cmd/godex/doc.go b/cmd/godex/doc.go
new file mode 100644
index 0000000..ceb7c2f
--- /dev/null
+++ b/cmd/godex/doc.go
@@ -0,0 +1,69 @@
+// Copyright 2014 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 godex command prints (dumps) exported information of packages
+// or selected package objects.
+//
+// In contrast to godoc, godex extracts this information from compiled
+// object files. Hence the exported data is truly what a compiler will
+// see, at the cost of missing commentary.
+//
+// Usage: godex [flags] {path[.name]}
+//
+// Each argument must be a (possibly partial) package path, optionally
+// followed by a dot and the name of a package object:
+//
+//	godex math
+//	godex math.Sin
+//	godex math.Sin fmt.Printf
+//	godex go/types
+//
+// godex automatically tries all possible package path prefixes if only a
+// partial package path is given. For instance, for the path "go/types",
+// godex prepends "golang.org/x/tools".
+//
+// The prefixes are computed by searching the directories specified by
+// the GOROOT and GOPATH environment variables (and by excluding the
+// build OS- and architecture-specific directory names from the path).
+// The search order is depth-first and alphabetic; for a partial path
+// "foo", a package "a/foo" is found before "b/foo".
+//
+// Absolute and relative paths may be provided, which disable automatic
+// prefix generation:
+//
+//	godex $GOROOT/pkg/darwin_amd64/sort
+//	godex ./sort
+//
+// All but the last path element may contain dots; a dot in the last path
+// element separates the package path from the package object name. If the
+// last path element contains a dot, terminate the argument with another
+// dot (indicating an empty object name). For instance, the path for a
+// package foo.bar would be specified as in:
+//
+//	godex foo.bar.
+//
+// The flags are:
+//
+//	-s=""
+//		only consider packages from src, where src is one of the supported compilers
+//	-v=false
+//		verbose mode
+//
+// The following sources (-s arguments) are supported:
+//
+//	gc
+//		gc-generated object files
+//	gccgo
+//		gccgo-generated object files
+//	gccgo-new
+//		gccgo-generated object files using a condensed format (experimental)
+//	source
+//		(uncompiled) source code (not yet implemented)
+//
+// If no -s argument is provided, godex will try to find a matching source.
+//
+package main // import "golang.org/x/tools/cmd/godex"
+
+// BUG(gri): support for -s=source is not yet implemented
+// BUG(gri): gccgo-importing appears to have occasional problems stalling godex; try -s=gc as work-around
diff --git a/cmd/godex/gc.go b/cmd/godex/gc.go
new file mode 100644
index 0000000..85335b9
--- /dev/null
+++ b/cmd/godex/gc.go
@@ -0,0 +1,15 @@
+// Copyright 2014 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.
+
+// This file implements access to gc-generated export data.
+
+package main
+
+import (
+	"golang.org/x/tools/go/gcimporter"
+)
+
+func init() {
+	register("gc", gcimporter.Import)
+}
diff --git a/cmd/godex/gccgo.go b/cmd/godex/gccgo.go
new file mode 100644
index 0000000..aee2d8e
--- /dev/null
+++ b/cmd/godex/gccgo.go
@@ -0,0 +1,40 @@
+// Copyright 2014 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.
+
+// This file implements access to gccgo-generated export data.
+
+package main
+
+import (
+	"golang.org/x/tools/go/gccgoimporter"
+	"golang.org/x/tools/go/types"
+)
+
+var (
+	initmap = make(map[*types.Package]gccgoimporter.InitData)
+)
+
+func init() {
+	incpaths := []string{"/"}
+
+	// importer for default gccgo
+	var inst gccgoimporter.GccgoInstallation
+	inst.InitFromDriver("gccgo")
+	register("gccgo", inst.GetImporter(incpaths, initmap))
+}
+
+// Print the extra gccgo compiler data for this package, if it exists.
+func (p *printer) printGccgoExtra(pkg *types.Package) {
+	if initdata, ok := initmap[pkg]; ok {
+		p.printf("/*\npriority %d\n", initdata.Priority)
+
+		p.printDecl("init", len(initdata.Inits), func() {
+			for _, init := range initdata.Inits {
+				p.printf("%s %s %d\n", init.Name, init.InitFunc, init.Priority)
+			}
+		})
+
+		p.print("*/\n")
+	}
+}
diff --git a/cmd/godex/godex.go b/cmd/godex/godex.go
new file mode 100644
index 0000000..dee0990
--- /dev/null
+++ b/cmd/godex/godex.go
@@ -0,0 +1,207 @@
+// Copyright 2014 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 main
+
+import (
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strings"
+
+	"golang.org/x/tools/go/types"
+)
+
+var (
+	source  = flag.String("s", "", "only consider packages from src, where src is one of the supported compilers")
+	verbose = flag.Bool("v", false, "verbose mode")
+)
+
+// lists of registered sources and corresponding importers
+var (
+	sources      []string
+	importers    []types.Importer
+	importFailed = errors.New("import failed")
+)
+
+// map of imported packages
+var packages = make(map[string]*types.Package)
+
+func usage() {
+	fmt.Fprintln(os.Stderr, "usage: godex [flags] {path|qualifiedIdent}")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func report(msg string) {
+	fmt.Fprintln(os.Stderr, "error: "+msg)
+	os.Exit(2)
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	if flag.NArg() == 0 {
+		report("no package name, path, or file provided")
+	}
+
+	imp := tryImports
+	if *source != "" {
+		imp = lookup(*source)
+		if imp == nil {
+			report("source (-s argument) must be one of: " + strings.Join(sources, ", "))
+		}
+	}
+
+	for _, arg := range flag.Args() {
+		path, name := splitPathIdent(arg)
+		logf("\tprocessing %q: path = %q, name = %s\n", arg, path, name)
+
+		// generate possible package path prefixes
+		// (at the moment we do this for each argument - should probably cache the generated prefixes)
+		prefixes := make(chan string)
+		go genPrefixes(prefixes, !filepath.IsAbs(path) && !build.IsLocalImport(path))
+
+		// import package
+		pkg, err := tryPrefixes(packages, prefixes, path, imp)
+		if err != nil {
+			logf("\t=> ignoring %q: %s\n", path, err)
+			continue
+		}
+
+		// filter objects if needed
+		var filter func(types.Object) bool
+		if name != "" {
+			filter = func(obj types.Object) bool {
+				// TODO(gri) perhaps use regular expression matching here?
+				return obj.Name() == name
+			}
+		}
+
+		// print contents
+		print(os.Stdout, pkg, filter)
+	}
+}
+
+func logf(format string, args ...interface{}) {
+	if *verbose {
+		fmt.Fprintf(os.Stderr, format, args...)
+	}
+}
+
+// splitPathIdent splits a path.name argument into its components.
+// All but the last path element may contain dots.
+func splitPathIdent(arg string) (path, name string) {
+	if i := strings.LastIndex(arg, "."); i >= 0 {
+		if j := strings.LastIndex(arg, "/"); j < i {
+			// '.' is not part of path
+			path = arg[:i]
+			name = arg[i+1:]
+			return
+		}
+	}
+	path = arg
+	return
+}
+
+// tryPrefixes tries to import the package given by (the possibly partial) path using the given importer imp
+// by prepending all possible prefixes to path. It returns with the first package that it could import, or
+// with an error.
+func tryPrefixes(packages map[string]*types.Package, prefixes chan string, path string, imp types.Importer) (pkg *types.Package, err error) {
+	for prefix := range prefixes {
+		actual := path
+		if prefix == "" {
+			// don't use filepath.Join as it will sanitize the path and remove
+			// a leading dot and then the path is not recognized as a relative
+			// package path by the importers anymore
+			logf("\ttrying no prefix\n")
+		} else {
+			actual = filepath.Join(prefix, path)
+			logf("\ttrying prefix %q\n", prefix)
+		}
+		pkg, err = imp(packages, actual)
+		if err == nil {
+			break
+		}
+		logf("\t=> importing %q failed: %s\n", actual, err)
+	}
+	return
+}
+
+// tryImports is an importer that tries all registered importers
+// successively until one of them succeeds or all of them failed.
+func tryImports(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
+	for i, imp := range importers {
+		logf("\t\ttrying %s import\n", sources[i])
+		pkg, err = imp(packages, path)
+		if err == nil {
+			break
+		}
+		logf("\t\t=> %s import failed: %s\n", sources[i], err)
+	}
+	return
+}
+
+// protect protects an importer imp from panics and returns the protected importer.
+func protect(imp types.Importer) types.Importer {
+	return func(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
+		defer func() {
+			if recover() != nil {
+				pkg = nil
+				err = importFailed
+			}
+		}()
+		return imp(packages, path)
+	}
+}
+
+// register registers an importer imp for a given source src.
+func register(src string, imp types.Importer) {
+	if lookup(src) != nil {
+		panic(src + " importer already registered")
+	}
+	sources = append(sources, src)
+	importers = append(importers, protect(imp))
+}
+
+// lookup returns the importer imp for a given source src.
+func lookup(src string) types.Importer {
+	for i, s := range sources {
+		if s == src {
+			return importers[i]
+		}
+	}
+	return nil
+}
+
+func genPrefixes(out chan string, all bool) {
+	out <- ""
+	if all {
+		platform := build.Default.GOOS + "_" + build.Default.GOARCH
+		dirnames := append([]string{build.Default.GOROOT}, filepath.SplitList(build.Default.GOPATH)...)
+		for _, dirname := range dirnames {
+			walkDir(filepath.Join(dirname, "pkg", platform), "", out)
+		}
+	}
+	close(out)
+}
+
+func walkDir(dirname, prefix string, out chan string) {
+	fiList, err := ioutil.ReadDir(dirname)
+	if err != nil {
+		return
+	}
+	for _, fi := range fiList {
+		if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") {
+			prefix := filepath.Join(prefix, fi.Name())
+			out <- prefix
+			walkDir(filepath.Join(dirname, fi.Name()), prefix, out)
+		}
+	}
+}
diff --git a/cmd/godex/print.go b/cmd/godex/print.go
new file mode 100644
index 0000000..e519f41
--- /dev/null
+++ b/cmd/godex/print.go
@@ -0,0 +1,368 @@
+// Copyright 2014 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"go/token"
+	"io"
+	"math/big"
+
+	"golang.org/x/tools/go/exact"
+	"golang.org/x/tools/go/types"
+)
+
+// TODO(gri) use tabwriter for alignment?
+
+func print(w io.Writer, pkg *types.Package, filter func(types.Object) bool) {
+	var p printer
+	p.pkg = pkg
+	p.printPackage(pkg, filter)
+	p.printGccgoExtra(pkg)
+	io.Copy(w, &p.buf)
+}
+
+type printer struct {
+	pkg    *types.Package
+	buf    bytes.Buffer
+	indent int  // current indentation level
+	last   byte // last byte written
+}
+
+func (p *printer) print(s string) {
+	// Write the string one byte at a time. We care about the presence of
+	// newlines for indentation which we will see even in the presence of
+	// (non-corrupted) Unicode; no need to read one rune at a time.
+	for i := 0; i < len(s); i++ {
+		ch := s[i]
+		if ch != '\n' && p.last == '\n' {
+			// Note: This could lead to a range overflow for very large
+			// indentations, but it's extremely unlikely to happen for
+			// non-pathological code.
+			p.buf.WriteString("\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"[:p.indent])
+		}
+		p.buf.WriteByte(ch)
+		p.last = ch
+	}
+}
+
+func (p *printer) printf(format string, args ...interface{}) {
+	p.print(fmt.Sprintf(format, args...))
+}
+
+// methodsFor returns the named type and corresponding methods if the type
+// denoted by obj is not an interface and has methods. Otherwise it returns
+// the zero value.
+func methodsFor(obj *types.TypeName) (*types.Named, []*types.Selection) {
+	named, _ := obj.Type().(*types.Named)
+	if named == nil {
+		// A type name's type can also be the
+		// exported basic type unsafe.Pointer.
+		return nil, nil
+	}
+	if _, ok := named.Underlying().(*types.Interface); ok {
+		// ignore interfaces
+		return nil, nil
+	}
+	methods := combinedMethodSet(named)
+	if len(methods) == 0 {
+		return nil, nil
+	}
+	return named, methods
+}
+
+func (p *printer) printPackage(pkg *types.Package, filter func(types.Object) bool) {
+	// collect objects by kind
+	var (
+		consts   []*types.Const
+		typem    []*types.Named    // non-interface types with methods
+		typez    []*types.TypeName // interfaces or types without methods
+		vars     []*types.Var
+		funcs    []*types.Func
+		builtins []*types.Builtin
+		methods  = make(map[*types.Named][]*types.Selection) // method sets for named types
+	)
+	scope := pkg.Scope()
+	for _, name := range scope.Names() {
+		obj := scope.Lookup(name)
+		if obj.Exported() {
+			// collect top-level exported and possibly filtered objects
+			if filter == nil || filter(obj) {
+				switch obj := obj.(type) {
+				case *types.Const:
+					consts = append(consts, obj)
+				case *types.TypeName:
+					// group into types with methods and types without
+					if named, m := methodsFor(obj); named != nil {
+						typem = append(typem, named)
+						methods[named] = m
+					} else {
+						typez = append(typez, obj)
+					}
+				case *types.Var:
+					vars = append(vars, obj)
+				case *types.Func:
+					funcs = append(funcs, obj)
+				case *types.Builtin:
+					// for unsafe.Sizeof, etc.
+					builtins = append(builtins, obj)
+				}
+			}
+		} else if filter == nil {
+			// no filtering: collect top-level unexported types with methods
+			if obj, _ := obj.(*types.TypeName); obj != nil {
+				// see case *types.TypeName above
+				if named, m := methodsFor(obj); named != nil {
+					typem = append(typem, named)
+					methods[named] = m
+				}
+			}
+		}
+	}
+
+	p.printf("package %s  // %q\n", pkg.Name(), pkg.Path())
+
+	p.printDecl("const", len(consts), func() {
+		for _, obj := range consts {
+			p.printObj(obj)
+			p.print("\n")
+		}
+	})
+
+	p.printDecl("var", len(vars), func() {
+		for _, obj := range vars {
+			p.printObj(obj)
+			p.print("\n")
+		}
+	})
+
+	p.printDecl("type", len(typez), func() {
+		for _, obj := range typez {
+			p.printf("%s ", obj.Name())
+			p.writeType(p.pkg, obj.Type().Underlying())
+			p.print("\n")
+		}
+	})
+
+	// non-interface types with methods
+	for _, named := range typem {
+		first := true
+		if obj := named.Obj(); obj.Exported() {
+			if first {
+				p.print("\n")
+				first = false
+			}
+			p.printf("type %s ", obj.Name())
+			p.writeType(p.pkg, named.Underlying())
+			p.print("\n")
+		}
+		for _, m := range methods[named] {
+			if obj := m.Obj(); obj.Exported() {
+				if first {
+					p.print("\n")
+					first = false
+				}
+				p.printFunc(m.Recv(), obj.(*types.Func))
+				p.print("\n")
+			}
+		}
+	}
+
+	if len(funcs) > 0 {
+		p.print("\n")
+		for _, obj := range funcs {
+			p.printFunc(nil, obj)
+			p.print("\n")
+		}
+	}
+
+	// TODO(gri) better handling of builtins (package unsafe only)
+	if len(builtins) > 0 {
+		p.print("\n")
+		for _, obj := range builtins {
+			p.printf("func %s() // builtin\n", obj.Name())
+		}
+	}
+
+	p.print("\n")
+}
+
+func (p *printer) printDecl(keyword string, n int, printGroup func()) {
+	switch n {
+	case 0:
+		// nothing to do
+	case 1:
+		p.printf("\n%s ", keyword)
+		printGroup()
+	default:
+		p.printf("\n%s (\n", keyword)
+		p.indent++
+		printGroup()
+		p.indent--
+		p.print(")\n")
+	}
+}
+
+// absInt returns the absolute value of v as a *big.Int.
+// v must be a numeric value.
+func absInt(v exact.Value) *big.Int {
+	// compute big-endian representation of v
+	b := exact.Bytes(v) // little-endian
+	for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
+		b[i], b[j] = b[j], b[i]
+	}
+	return new(big.Int).SetBytes(b)
+}
+
+var (
+	one = big.NewRat(1, 1)
+	ten = big.NewRat(10, 1)
+)
+
+// floatString returns the string representation for a
+// numeric value v in normalized floating-point format.
+func floatString(v exact.Value) string {
+	if exact.Sign(v) == 0 {
+		return "0.0"
+	}
+	// x != 0
+
+	// convert |v| into a big.Rat x
+	x := new(big.Rat).SetFrac(absInt(exact.Num(v)), absInt(exact.Denom(v)))
+
+	// normalize x and determine exponent e
+	// (This is not very efficient, but also not speed-critical.)
+	var e int
+	for x.Cmp(ten) >= 0 {
+		x.Quo(x, ten)
+		e++
+	}
+	for x.Cmp(one) < 0 {
+		x.Mul(x, ten)
+		e--
+	}
+
+	// TODO(gri) Values such as 1/2 are easier to read in form 0.5
+	// rather than 5.0e-1. Similarly, 1.0e1 is easier to read as
+	// 10.0. Fine-tune best exponent range for readability.
+
+	s := x.FloatString(100) // good-enough precision
+
+	// trim trailing 0's
+	i := len(s)
+	for i > 0 && s[i-1] == '0' {
+		i--
+	}
+	s = s[:i]
+
+	// add a 0 if the number ends in decimal point
+	if len(s) > 0 && s[len(s)-1] == '.' {
+		s += "0"
+	}
+
+	// add exponent and sign
+	if e != 0 {
+		s += fmt.Sprintf("e%+d", e)
+	}
+	if exact.Sign(v) < 0 {
+		s = "-" + s
+	}
+
+	// TODO(gri) If v is a "small" fraction (i.e., numerator and denominator
+	// are just a small number of decimal digits), add the exact fraction as
+	// a comment. For instance: 3.3333...e-1 /* = 1/3 */
+
+	return s
+}
+
+// valString returns the string representation for the value v.
+// Setting floatFmt forces an integer value to be formatted in
+// normalized floating-point format.
+// TODO(gri) Move this code into package exact.
+func valString(v exact.Value, floatFmt bool) string {
+	switch v.Kind() {
+	case exact.Int:
+		if floatFmt {
+			return floatString(v)
+		}
+	case exact.Float:
+		return floatString(v)
+	case exact.Complex:
+		re := exact.Real(v)
+		im := exact.Imag(v)
+		var s string
+		if exact.Sign(re) != 0 {
+			s = floatString(re)
+			if exact.Sign(im) >= 0 {
+				s += " + "
+			} else {
+				s += " - "
+				im = exact.UnaryOp(token.SUB, im, 0) // negate im
+			}
+		}
+		// im != 0, otherwise v would be exact.Int or exact.Float
+		return s + floatString(im) + "i"
+	}
+	return v.String()
+}
+
+func (p *printer) printObj(obj types.Object) {
+	p.print(obj.Name())
+
+	typ, basic := obj.Type().Underlying().(*types.Basic)
+	if basic && typ.Info()&types.IsUntyped != 0 {
+		// don't write untyped types
+	} else {
+		p.print(" ")
+		p.writeType(p.pkg, obj.Type())
+	}
+
+	if obj, ok := obj.(*types.Const); ok {
+		floatFmt := basic && typ.Info()&(types.IsFloat|types.IsComplex) != 0
+		p.print(" = ")
+		p.print(valString(obj.Val(), floatFmt))
+	}
+}
+
+func (p *printer) printFunc(recvType types.Type, obj *types.Func) {
+	p.print("func ")
+	sig := obj.Type().(*types.Signature)
+	if recvType != nil {
+		p.print("(")
+		p.writeType(p.pkg, recvType)
+		p.print(") ")
+	}
+	p.print(obj.Name())
+	p.writeSignature(p.pkg, sig)
+}
+
+// combinedMethodSet returns the method set for a named type T
+// merged with all the methods of *T that have different names than
+// the methods of T.
+//
+// combinedMethodSet is analogous to types/typeutil.IntuitiveMethodSet
+// but doesn't require a MethodSetCache.
+// TODO(gri) If this functionality doesn't change over time, consider
+// just calling IntuitiveMethodSet eventually.
+func combinedMethodSet(T *types.Named) []*types.Selection {
+	// method set for T
+	mset := types.NewMethodSet(T)
+	var res []*types.Selection
+	for i, n := 0, mset.Len(); i < n; i++ {
+		res = append(res, mset.At(i))
+	}
+
+	// add all *T methods with names different from T methods
+	pmset := types.NewMethodSet(types.NewPointer(T))
+	for i, n := 0, pmset.Len(); i < n; i++ {
+		pm := pmset.At(i)
+		if obj := pm.Obj(); mset.Lookup(obj.Pkg(), obj.Name()) == nil {
+			res = append(res, pm)
+		}
+	}
+
+	return res
+}
diff --git a/cmd/godex/source.go b/cmd/godex/source.go
new file mode 100644
index 0000000..22d7813
--- /dev/null
+++ b/cmd/godex/source.go
@@ -0,0 +1,19 @@
+// Copyright 2014 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.
+
+// This file implements access to export data from source.
+
+package main
+
+import (
+	"golang.org/x/tools/go/types"
+)
+
+func init() {
+	register("source", sourceImporter)
+}
+
+func sourceImporter(packages map[string]*types.Package, path string) (*types.Package, error) {
+	panic("unimplemented")
+}
diff --git a/cmd/godex/writetype.go b/cmd/godex/writetype.go
new file mode 100644
index 0000000..10c8e65
--- /dev/null
+++ b/cmd/godex/writetype.go
@@ -0,0 +1,242 @@
+// Copyright 2014 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.
+
+// This file implements writing of types. The functionality is lifted
+// directly from go/types, but now contains various modifications for
+// nicer output.
+//
+// TODO(gri) back-port once we have a fixed interface and once the
+// go/types API is not frozen anymore for the 1.3 release; and remove
+// this implementation if possible.
+
+package main
+
+import "golang.org/x/tools/go/types"
+
+func (p *printer) writeType(this *types.Package, typ types.Type) {
+	p.writeTypeInternal(this, typ, make([]types.Type, 8))
+}
+
+// From go/types - leave for now to ease back-porting this code.
+const GcCompatibilityMode = false
+
+func (p *printer) writeTypeInternal(this *types.Package, typ types.Type, visited []types.Type) {
+	// Theoretically, this is a quadratic lookup algorithm, but in
+	// practice deeply nested composite types with unnamed component
+	// types are uncommon. This code is likely more efficient than
+	// using a map.
+	for _, t := range visited {
+		if t == typ {
+			p.printf("â—‹%T", typ) // cycle to typ
+			return
+		}
+	}
+	visited = append(visited, typ)
+
+	switch t := typ.(type) {
+	case nil:
+		p.print("<nil>")
+
+	case *types.Basic:
+		if t.Kind() == types.UnsafePointer {
+			p.print("unsafe.")
+		}
+		if GcCompatibilityMode {
+			// forget the alias names
+			switch t.Kind() {
+			case types.Byte:
+				t = types.Typ[types.Uint8]
+			case types.Rune:
+				t = types.Typ[types.Int32]
+			}
+		}
+		p.print(t.Name())
+
+	case *types.Array:
+		p.printf("[%d]", t.Len())
+		p.writeTypeInternal(this, t.Elem(), visited)
+
+	case *types.Slice:
+		p.print("[]")
+		p.writeTypeInternal(this, t.Elem(), visited)
+
+	case *types.Struct:
+		n := t.NumFields()
+		if n == 0 {
+			p.print("struct{}")
+			return
+		}
+
+		p.print("struct {\n")
+		p.indent++
+		for i := 0; i < n; i++ {
+			f := t.Field(i)
+			if !f.Anonymous() {
+				p.printf("%s ", f.Name())
+			}
+			p.writeTypeInternal(this, f.Type(), visited)
+			if tag := t.Tag(i); tag != "" {
+				p.printf(" %q", tag)
+			}
+			p.print("\n")
+		}
+		p.indent--
+		p.print("}")
+
+	case *types.Pointer:
+		p.print("*")
+		p.writeTypeInternal(this, t.Elem(), visited)
+
+	case *types.Tuple:
+		p.writeTuple(this, t, false, visited)
+
+	case *types.Signature:
+		p.print("func")
+		p.writeSignatureInternal(this, t, visited)
+
+	case *types.Interface:
+		// We write the source-level methods and embedded types rather
+		// than the actual method set since resolved method signatures
+		// may have non-printable cycles if parameters have anonymous
+		// interface types that (directly or indirectly) embed the
+		// current interface. For instance, consider the result type
+		// of m:
+		//
+		//     type T interface{
+		//         m() interface{ T }
+		//     }
+		//
+		n := t.NumMethods()
+		if n == 0 {
+			p.print("interface{}")
+			return
+		}
+
+		p.print("interface {\n")
+		p.indent++
+		if GcCompatibilityMode {
+			// print flattened interface
+			// (useful to compare against gc-generated interfaces)
+			for i := 0; i < n; i++ {
+				m := t.Method(i)
+				p.print(m.Name())
+				p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
+				p.print("\n")
+			}
+		} else {
+			// print explicit interface methods and embedded types
+			for i, n := 0, t.NumExplicitMethods(); i < n; i++ {
+				m := t.ExplicitMethod(i)
+				p.print(m.Name())
+				p.writeSignatureInternal(this, m.Type().(*types.Signature), visited)
+				p.print("\n")
+			}
+			for i, n := 0, t.NumEmbeddeds(); i < n; i++ {
+				typ := t.Embedded(i)
+				p.writeTypeInternal(this, typ, visited)
+				p.print("\n")
+			}
+		}
+		p.indent--
+		p.print("}")
+
+	case *types.Map:
+		p.print("map[")
+		p.writeTypeInternal(this, t.Key(), visited)
+		p.print("]")
+		p.writeTypeInternal(this, t.Elem(), visited)
+
+	case *types.Chan:
+		var s string
+		var parens bool
+		switch t.Dir() {
+		case types.SendRecv:
+			s = "chan "
+			// chan (<-chan T) requires parentheses
+			if c, _ := t.Elem().(*types.Chan); c != nil && c.Dir() == types.RecvOnly {
+				parens = true
+			}
+		case types.SendOnly:
+			s = "chan<- "
+		case types.RecvOnly:
+			s = "<-chan "
+		default:
+			panic("unreachable")
+		}
+		p.print(s)
+		if parens {
+			p.print("(")
+		}
+		p.writeTypeInternal(this, t.Elem(), visited)
+		if parens {
+			p.print(")")
+		}
+
+	case *types.Named:
+		s := "<Named w/o object>"
+		if obj := t.Obj(); obj != nil {
+			if pkg := obj.Pkg(); pkg != nil {
+				if pkg != this {
+					p.print(pkg.Path())
+					p.print(".")
+				}
+				// TODO(gri): function-local named types should be displayed
+				// differently from named types at package level to avoid
+				// ambiguity.
+			}
+			s = obj.Name()
+		}
+		p.print(s)
+
+	default:
+		// For externally defined implementations of Type.
+		p.print(t.String())
+	}
+}
+
+func (p *printer) writeTuple(this *types.Package, tup *types.Tuple, variadic bool, visited []types.Type) {
+	p.print("(")
+	for i, n := 0, tup.Len(); i < n; i++ {
+		if i > 0 {
+			p.print(", ")
+		}
+		v := tup.At(i)
+		if name := v.Name(); name != "" {
+			p.print(name)
+			p.print(" ")
+		}
+		typ := v.Type()
+		if variadic && i == n-1 {
+			p.print("...")
+			typ = typ.(*types.Slice).Elem()
+		}
+		p.writeTypeInternal(this, typ, visited)
+	}
+	p.print(")")
+}
+
+func (p *printer) writeSignature(this *types.Package, sig *types.Signature) {
+	p.writeSignatureInternal(this, sig, make([]types.Type, 8))
+}
+
+func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) {
+	p.writeTuple(this, sig.Params(), sig.Variadic(), visited)
+
+	res := sig.Results()
+	n := res.Len()
+	if n == 0 {
+		// no result
+		return
+	}
+
+	p.print(" ")
+	if n == 1 && res.At(0).Name() == "" {
+		// single unnamed result
+		p.writeTypeInternal(this, res.At(0).Type(), visited)
+		return
+	}
+
+	// multiple or named result(s)
+	p.writeTuple(this, res, false, visited)
+}
diff --git a/cmd/godoc/README.godoc-app b/cmd/godoc/README.godoc-app
new file mode 100644
index 0000000..50a0516
--- /dev/null
+++ b/cmd/godoc/README.godoc-app
@@ -0,0 +1,56 @@
+godoc on appengine
+------------------
+
+Prerequisites
+-------------
+
+* Go appengine SDK
+  https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Go
+
+* Go sources at tip under $GOROOT
+
+* Godoc sources at tip inside $GOPATH
+  (go get -d golang.org/x/tools/cmd/godoc)
+
+
+Directory structure
+-------------------
+
+* Let $APPDIR be the directory containing the app engine files.
+  (e.g., $APPDIR=$HOME/godoc-app)
+
+* $APPDIR contains the following entries (this may change depending on
+  app-engine release and version of godoc):
+
+	app.yaml
+	golang.org/x/tools/cmd/godoc
+	godoc.zip
+	index.split.*
+
+* The app.yaml file is set up per app engine documentation.
+  For instance:
+
+	application: godoc-app
+	version: 1
+	runtime: go
+	api_version: go1
+
+	handlers:
+	- url: /.*
+	  script: _go_app
+
+
+Configuring and running godoc
+-----------------------------
+
+To configure godoc, run
+
+	bash setup-godoc-app.bash
+
+to prepare an $APPDIR as described above. See the script for details on usage.
+
+To run godoc locally, using the App Engine development server, run
+
+	<path to go_appengine>/dev_appserver.py $APPDIR
+
+godoc should come up at http://localhost:8080 .
diff --git a/cmd/godoc/appinit.go b/cmd/godoc/appinit.go
new file mode 100644
index 0000000..3d6a921
--- /dev/null
+++ b/cmd/godoc/appinit.go
@@ -0,0 +1,67 @@
+// 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.
+
+// +build appengine
+
+package main
+
+// This file replaces main.go when running godoc under app-engine.
+// See README.godoc-app for details.
+
+import (
+	"archive/zip"
+	"log"
+	"path"
+	"regexp"
+
+	"golang.org/x/tools/godoc"
+	"golang.org/x/tools/godoc/static"
+	"golang.org/x/tools/godoc/vfs"
+	"golang.org/x/tools/godoc/vfs/mapfs"
+	"golang.org/x/tools/godoc/vfs/zipfs"
+)
+
+func init() {
+	playEnabled = true
+
+	log.Println("initializing godoc ...")
+	log.Printf(".zip file   = %s", zipFilename)
+	log.Printf(".zip GOROOT = %s", zipGoroot)
+	log.Printf("index files = %s", indexFilenames)
+
+	goroot := path.Join("/", zipGoroot) // fsHttp paths are relative to '/'
+
+	// read .zip file and set up file systems
+	const zipfile = zipFilename
+	rc, err := zip.OpenReader(zipfile)
+	if err != nil {
+		log.Fatalf("%s: %s\n", zipfile, err)
+	}
+	// rc is never closed (app running forever)
+	fs.Bind("/", zipfs.New(rc, zipFilename), goroot, vfs.BindReplace)
+	fs.Bind("/lib/godoc", mapfs.New(static.Files), "/", vfs.BindReplace)
+
+	corpus := godoc.NewCorpus(fs)
+	corpus.Verbose = false
+	corpus.MaxResults = 10000 // matches flag default in main.go
+	corpus.IndexEnabled = true
+	corpus.IndexFiles = indexFilenames
+	if err := corpus.Init(); err != nil {
+		log.Fatal(err)
+	}
+	corpus.IndexDirectory = indexDirectoryDefault
+	go corpus.RunIndexer()
+
+	pres = godoc.NewPresentation(corpus)
+	pres.TabWidth = 8
+	pres.ShowPlayground = true
+	pres.ShowExamples = true
+	pres.DeclLinks = true
+	pres.NotesRx = regexp.MustCompile("BUG")
+
+	readTemplates(pres, true)
+	registerHandlers(pres)
+
+	log.Println("godoc initialization complete")
+}
diff --git a/cmd/godoc/blog.go b/cmd/godoc/blog.go
new file mode 100644
index 0000000..dec4732
--- /dev/null
+++ b/cmd/godoc/blog.go
@@ -0,0 +1,81 @@
+// Copyright 2013 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 main
+
+import (
+	"fmt"
+	"go/build"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"sync"
+
+	"golang.org/x/tools/blog"
+	"golang.org/x/tools/godoc/redirect"
+)
+
+const (
+	blogRepo = "golang.org/x/blog"
+	blogURL  = "http://blog.golang.org/"
+	blogPath = "/blog/"
+)
+
+var (
+	blogServer   http.Handler // set by blogInit
+	blogInitOnce sync.Once
+	playEnabled  bool
+)
+
+func init() {
+	// Initialize blog only when first accessed.
+	http.HandleFunc(blogPath, func(w http.ResponseWriter, r *http.Request) {
+		blogInitOnce.Do(blogInit)
+		blogServer.ServeHTTP(w, r)
+	})
+}
+
+func blogInit() {
+	// Binary distributions will include the blog content in "/blog".
+	root := filepath.Join(runtime.GOROOT(), "blog")
+
+	// Prefer content from go.blog repository if present.
+	if pkg, err := build.Import(blogRepo, "", build.FindOnly); err == nil {
+		root = pkg.Dir
+	}
+
+	// If content is not available fall back to redirect.
+	if fi, err := os.Stat(root); err != nil || !fi.IsDir() {
+		fmt.Fprintf(os.Stderr, "Blog content not available locally. "+
+			"To install, run \n\tgo get %v\n", blogRepo)
+		blogServer = http.HandlerFunc(blogRedirectHandler)
+		return
+	}
+
+	s, err := blog.NewServer(blog.Config{
+		BaseURL:      blogPath,
+		BasePath:     strings.TrimSuffix(blogPath, "/"),
+		ContentPath:  filepath.Join(root, "content"),
+		TemplatePath: filepath.Join(root, "template"),
+		HomeArticles: 5,
+		PlayEnabled:  playEnabled,
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+	blogServer = s
+}
+
+func blogRedirectHandler(w http.ResponseWriter, r *http.Request) {
+	if r.URL.Path == blogPath {
+		http.Redirect(w, r, blogURL, http.StatusFound)
+		return
+	}
+	blogPrefixHandler.ServeHTTP(w, r)
+}
+
+var blogPrefixHandler = redirect.PrefixHandler(blogPath, blogURL)
diff --git a/cmd/godoc/codewalk.go b/cmd/godoc/codewalk.go
new file mode 100644
index 0000000..e3bf5cd
--- /dev/null
+++ b/cmd/godoc/codewalk.go
@@ -0,0 +1,523 @@
+// 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 /doc/codewalk/ tree is synthesized from codewalk descriptions,
+// files named $GOROOT/doc/codewalk/*.xml.
+// For an example and a description of the format, see
+// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
+// and see http://localhost:6060/doc/codewalk/codewalk .
+// That page is itself a codewalk; the source code for it is
+// $GOROOT/doc/codewalk/codewalk.xml.
+
+package main
+
+import (
+	"bytes"
+	"encoding/xml"
+	"errors"
+	"fmt"
+	"io"
+	"log"
+	"net/http"
+	"os"
+	pathpkg "path"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+	"text/template"
+	"unicode/utf8"
+
+	"golang.org/x/tools/godoc"
+	"golang.org/x/tools/godoc/vfs"
+)
+
+var codewalkHTML, codewalkdirHTML *template.Template
+
+// Handler for /doc/codewalk/ and below.
+func codewalk(w http.ResponseWriter, r *http.Request) {
+	relpath := r.URL.Path[len("/doc/codewalk/"):]
+	abspath := r.URL.Path
+
+	r.ParseForm()
+	if f := r.FormValue("fileprint"); f != "" {
+		codewalkFileprint(w, r, f)
+		return
+	}
+
+	// If directory exists, serve list of code walks.
+	dir, err := fs.Lstat(abspath)
+	if err == nil && dir.IsDir() {
+		codewalkDir(w, r, relpath, abspath)
+		return
+	}
+
+	// If file exists, serve using standard file server.
+	if err == nil {
+		pres.ServeFile(w, r)
+		return
+	}
+
+	// Otherwise append .xml and hope to find
+	// a codewalk description, but before trim
+	// the trailing /.
+	abspath = strings.TrimRight(abspath, "/")
+	cw, err := loadCodewalk(abspath + ".xml")
+	if err != nil {
+		log.Print(err)
+		pres.ServeError(w, r, relpath, err)
+		return
+	}
+
+	// Canonicalize the path and redirect if changed
+	if redir(w, r) {
+		return
+	}
+
+	pres.ServePage(w, godoc.Page{
+		Title:    "Codewalk: " + cw.Title,
+		Tabtitle: cw.Title,
+		Body:     applyTemplate(codewalkHTML, "codewalk", cw),
+	})
+}
+
+func redir(w http.ResponseWriter, r *http.Request) (redirected bool) {
+	canonical := pathpkg.Clean(r.URL.Path)
+	if !strings.HasSuffix(canonical, "/") {
+		canonical += "/"
+	}
+	if r.URL.Path != canonical {
+		url := *r.URL
+		url.Path = canonical
+		http.Redirect(w, r, url.String(), http.StatusMovedPermanently)
+		redirected = true
+	}
+	return
+}
+
+func applyTemplate(t *template.Template, name string, data interface{}) []byte {
+	var buf bytes.Buffer
+	if err := t.Execute(&buf, data); err != nil {
+		log.Printf("%s.Execute: %s", name, err)
+	}
+	return buf.Bytes()
+}
+
+// A Codewalk represents a single codewalk read from an XML file.
+type Codewalk struct {
+	Title string      `xml:"title,attr"`
+	File  []string    `xml:"file"`
+	Step  []*Codestep `xml:"step"`
+}
+
+// A Codestep is a single step in a codewalk.
+type Codestep struct {
+	// Filled in from XML
+	Src   string `xml:"src,attr"`
+	Title string `xml:"title,attr"`
+	XML   string `xml:",innerxml"`
+
+	// Derived from Src; not in XML.
+	Err    error
+	File   string
+	Lo     int
+	LoByte int
+	Hi     int
+	HiByte int
+	Data   []byte
+}
+
+// String method for printing in template.
+// Formats file address nicely.
+func (st *Codestep) String() string {
+	s := st.File
+	if st.Lo != 0 || st.Hi != 0 {
+		s += fmt.Sprintf(":%d", st.Lo)
+		if st.Lo != st.Hi {
+			s += fmt.Sprintf(",%d", st.Hi)
+		}
+	}
+	return s
+}
+
+// loadCodewalk reads a codewalk from the named XML file.
+func loadCodewalk(filename string) (*Codewalk, error) {
+	f, err := fs.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	cw := new(Codewalk)
+	d := xml.NewDecoder(f)
+	d.Entity = xml.HTMLEntity
+	err = d.Decode(cw)
+	if err != nil {
+		return nil, &os.PathError{Op: "parsing", Path: filename, Err: err}
+	}
+
+	// Compute file list, evaluate line numbers for addresses.
+	m := make(map[string]bool)
+	for _, st := range cw.Step {
+		i := strings.Index(st.Src, ":")
+		if i < 0 {
+			i = len(st.Src)
+		}
+		filename := st.Src[0:i]
+		data, err := vfs.ReadFile(fs, filename)
+		if err != nil {
+			st.Err = err
+			continue
+		}
+		if i < len(st.Src) {
+			lo, hi, err := addrToByteRange(st.Src[i+1:], 0, data)
+			if err != nil {
+				st.Err = err
+				continue
+			}
+			// Expand match to line boundaries.
+			for lo > 0 && data[lo-1] != '\n' {
+				lo--
+			}
+			for hi < len(data) && (hi == 0 || data[hi-1] != '\n') {
+				hi++
+			}
+			st.Lo = byteToLine(data, lo)
+			st.Hi = byteToLine(data, hi-1)
+		}
+		st.Data = data
+		st.File = filename
+		m[filename] = true
+	}
+
+	// Make list of files
+	cw.File = make([]string, len(m))
+	i := 0
+	for f := range m {
+		cw.File[i] = f
+		i++
+	}
+	sort.Strings(cw.File)
+
+	return cw, nil
+}
+
+// codewalkDir serves the codewalk directory listing.
+// It scans the directory for subdirectories or files named *.xml
+// and prepares a table.
+func codewalkDir(w http.ResponseWriter, r *http.Request, relpath, abspath string) {
+	type elem struct {
+		Name  string
+		Title string
+	}
+
+	dir, err := fs.ReadDir(abspath)
+	if err != nil {
+		log.Print(err)
+		pres.ServeError(w, r, relpath, err)
+		return
+	}
+	var v []interface{}
+	for _, fi := range dir {
+		name := fi.Name()
+		if fi.IsDir() {
+			v = append(v, &elem{name + "/", ""})
+		} else if strings.HasSuffix(name, ".xml") {
+			cw, err := loadCodewalk(abspath + "/" + name)
+			if err != nil {
+				continue
+			}
+			v = append(v, &elem{name[0 : len(name)-len(".xml")], cw.Title})
+		}
+	}
+
+	pres.ServePage(w, godoc.Page{
+		Title: "Codewalks",
+		Body:  applyTemplate(codewalkdirHTML, "codewalkdir", v),
+	})
+}
+
+// codewalkFileprint serves requests with ?fileprint=f&lo=lo&hi=hi.
+// The filename f has already been retrieved and is passed as an argument.
+// Lo and hi are the numbers of the first and last line to highlight
+// in the response.  This format is used for the middle window pane
+// of the codewalk pages.  It is a separate iframe and does not get
+// the usual godoc HTML wrapper.
+func codewalkFileprint(w http.ResponseWriter, r *http.Request, f string) {
+	abspath := f
+	data, err := vfs.ReadFile(fs, abspath)
+	if err != nil {
+		log.Print(err)
+		pres.ServeError(w, r, f, err)
+		return
+	}
+	lo, _ := strconv.Atoi(r.FormValue("lo"))
+	hi, _ := strconv.Atoi(r.FormValue("hi"))
+	if hi < lo {
+		hi = lo
+	}
+	lo = lineToByte(data, lo)
+	hi = lineToByte(data, hi+1)
+
+	// Put the mark 4 lines before lo, so that the iframe
+	// shows a few lines of context before the highlighted
+	// section.
+	n := 4
+	mark := lo
+	for ; mark > 0 && n > 0; mark-- {
+		if data[mark-1] == '\n' {
+			if n--; n == 0 {
+				break
+			}
+		}
+	}
+
+	io.WriteString(w, `<style type="text/css">@import "/doc/codewalk/codewalk.css";</style><pre>`)
+	template.HTMLEscape(w, data[0:mark])
+	io.WriteString(w, "<a name='mark'></a>")
+	template.HTMLEscape(w, data[mark:lo])
+	if lo < hi {
+		io.WriteString(w, "<div class='codewalkhighlight'>")
+		template.HTMLEscape(w, data[lo:hi])
+		io.WriteString(w, "</div>")
+	}
+	template.HTMLEscape(w, data[hi:])
+	io.WriteString(w, "</pre>")
+}
+
+// addrToByte evaluates the given address starting at offset start in data.
+// It returns the lo and hi byte offset of the matched region within data.
+// See http://plan9.bell-labs.com/sys/doc/sam/sam.html Table II
+// for details on the syntax.
+func addrToByteRange(addr string, start int, data []byte) (lo, hi int, err error) {
+	var (
+		dir        byte
+		prevc      byte
+		charOffset bool
+	)
+	lo = start
+	hi = start
+	for addr != "" && err == nil {
+		c := addr[0]
+		switch c {
+		default:
+			err = errors.New("invalid address syntax near " + string(c))
+		case ',':
+			if len(addr) == 1 {
+				hi = len(data)
+			} else {
+				_, hi, err = addrToByteRange(addr[1:], hi, data)
+			}
+			return
+
+		case '+', '-':
+			if prevc == '+' || prevc == '-' {
+				lo, hi, err = addrNumber(data, lo, hi, prevc, 1, charOffset)
+			}
+			dir = c
+
+		case '$':
+			lo = len(data)
+			hi = len(data)
+			if len(addr) > 1 {
+				dir = '+'
+			}
+
+		case '#':
+			charOffset = true
+
+		case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
+			var i int
+			for i = 1; i < len(addr); i++ {
+				if addr[i] < '0' || addr[i] > '9' {
+					break
+				}
+			}
+			var n int
+			n, err = strconv.Atoi(addr[0:i])
+			if err != nil {
+				break
+			}
+			lo, hi, err = addrNumber(data, lo, hi, dir, n, charOffset)
+			dir = 0
+			charOffset = false
+			prevc = c
+			addr = addr[i:]
+			continue
+
+		case '/':
+			var i, j int
+		Regexp:
+			for i = 1; i < len(addr); i++ {
+				switch addr[i] {
+				case '\\':
+					i++
+				case '/':
+					j = i + 1
+					break Regexp
+				}
+			}
+			if j == 0 {
+				j = i
+			}
+			pattern := addr[1:i]
+			lo, hi, err = addrRegexp(data, lo, hi, dir, pattern)
+			prevc = c
+			addr = addr[j:]
+			continue
+		}
+		prevc = c
+		addr = addr[1:]
+	}
+
+	if err == nil && dir != 0 {
+		lo, hi, err = addrNumber(data, lo, hi, dir, 1, charOffset)
+	}
+	if err != nil {
+		return 0, 0, err
+	}
+	return lo, hi, nil
+}
+
+// addrNumber applies the given dir, n, and charOffset to the address lo, hi.
+// dir is '+' or '-', n is the count, and charOffset is true if the syntax
+// used was #n.  Applying +n (or +#n) means to advance n lines
+// (or characters) after hi.  Applying -n (or -#n) means to back up n lines
+// (or characters) before lo.
+// The return value is the new lo, hi.
+func addrNumber(data []byte, lo, hi int, dir byte, n int, charOffset bool) (int, int, error) {
+	switch dir {
+	case 0:
+		lo = 0
+		hi = 0
+		fallthrough
+
+	case '+':
+		if charOffset {
+			pos := hi
+			for ; n > 0 && pos < len(data); n-- {
+				_, size := utf8.DecodeRune(data[pos:])
+				pos += size
+			}
+			if n == 0 {
+				return pos, pos, nil
+			}
+			break
+		}
+		// find next beginning of line
+		if hi > 0 {
+			for hi < len(data) && data[hi-1] != '\n' {
+				hi++
+			}
+		}
+		lo = hi
+		if n == 0 {
+			return lo, hi, nil
+		}
+		for ; hi < len(data); hi++ {
+			if data[hi] != '\n' {
+				continue
+			}
+			switch n--; n {
+			case 1:
+				lo = hi + 1
+			case 0:
+				return lo, hi + 1, nil
+			}
+		}
+
+	case '-':
+		if charOffset {
+			// Scan backward for bytes that are not UTF-8 continuation bytes.
+			pos := lo
+			for ; pos > 0 && n > 0; pos-- {
+				if data[pos]&0xc0 != 0x80 {
+					n--
+				}
+			}
+			if n == 0 {
+				return pos, pos, nil
+			}
+			break
+		}
+		// find earlier beginning of line
+		for lo > 0 && data[lo-1] != '\n' {
+			lo--
+		}
+		hi = lo
+		if n == 0 {
+			return lo, hi, nil
+		}
+		for ; lo >= 0; lo-- {
+			if lo > 0 && data[lo-1] != '\n' {
+				continue
+			}
+			switch n--; n {
+			case 1:
+				hi = lo
+			case 0:
+				return lo, hi, nil
+			}
+		}
+	}
+
+	return 0, 0, errors.New("address out of range")
+}
+
+// addrRegexp searches for pattern in the given direction starting at lo, hi.
+// The direction dir is '+' (search forward from hi) or '-' (search backward from lo).
+// Backward searches are unimplemented.
+func addrRegexp(data []byte, lo, hi int, dir byte, pattern string) (int, int, error) {
+	re, err := regexp.Compile(pattern)
+	if err != nil {
+		return 0, 0, err
+	}
+	if dir == '-' {
+		// Could implement reverse search using binary search
+		// through file, but that seems like overkill.
+		return 0, 0, errors.New("reverse search not implemented")
+	}
+	m := re.FindIndex(data[hi:])
+	if len(m) > 0 {
+		m[0] += hi
+		m[1] += hi
+	} else if hi > 0 {
+		// No match.  Wrap to beginning of data.
+		m = re.FindIndex(data)
+	}
+	if len(m) == 0 {
+		return 0, 0, errors.New("no match for " + pattern)
+	}
+	return m[0], m[1], nil
+}
+
+// lineToByte returns the byte index of the first byte of line n.
+// Line numbers begin at 1.
+func lineToByte(data []byte, n int) int {
+	if n <= 1 {
+		return 0
+	}
+	n--
+	for i, c := range data {
+		if c == '\n' {
+			if n--; n == 0 {
+				return i + 1
+			}
+		}
+	}
+	return len(data)
+}
+
+// byteToLine returns the number of the line containing the byte at index i.
+func byteToLine(data []byte, i int) int {
+	l := 1
+	for j, c := range data {
+		if j == i {
+			return l
+		}
+		if c == '\n' {
+			l++
+		}
+	}
+	return l
+}
diff --git a/cmd/godoc/dl.go b/cmd/godoc/dl.go
new file mode 100644
index 0000000..bd73831
--- /dev/null
+++ b/cmd/godoc/dl.go
@@ -0,0 +1,14 @@
+// Copyright 2014 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 main
+
+import "net/http"
+
+// Register a redirect handler for /dl/ to the golang.org download page.
+// This file will not be included when deploying godoc to golang.org.
+
+func init() {
+	http.Handle("/dl/", http.RedirectHandler("http://golang.org/dl/", http.StatusFound))
+}
diff --git a/cmd/godoc/doc.go b/cmd/godoc/doc.go
new file mode 100644
index 0000000..17cf23e
--- /dev/null
+++ b/cmd/godoc/doc.go
@@ -0,0 +1,146 @@
+// Copyright 2009 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.
+
+/*
+
+Godoc extracts and generates documentation for Go programs.
+
+It has two modes.
+
+Without the -http flag, it runs in command-line mode and prints plain text
+documentation to standard output and exits. If both a library package and
+a command with the same name exists, using the prefix cmd/ will force
+documentation on the command rather than the library package. If the -src
+flag is specified, godoc prints the exported interface of a package in Go
+source form, or the implementation of a specific exported language entity:
+
+	godoc fmt                # documentation for package fmt
+	godoc fmt Printf         # documentation for fmt.Printf
+	godoc cmd/go             # force documentation for the go command
+	godoc -src fmt           # fmt package interface in Go source form
+	godoc -src fmt Printf    # implementation of fmt.Printf
+
+In command-line mode, the -q flag enables search queries against a godoc running
+as a webserver. If no explicit server address is specified with the -server flag,
+godoc first tries localhost:6060 and then http://golang.org.
+
+	godoc -q Reader
+	godoc -q math.Sin
+	godoc -server=:6060 -q sin
+
+With the -http flag, it runs as a web server and presents the documentation as a
+web page.
+
+	godoc -http=:6060
+
+Usage:
+	godoc [flag] package [name ...]
+
+The flags are:
+	-v
+		verbose mode
+	-q
+		arguments are considered search queries: a legal query is a
+		single identifier (such as ToLower) or a qualified identifier
+		(such as math.Sin)
+	-src
+		print (exported) source in command-line mode
+	-tabwidth=4
+		width of tabs in units of spaces
+	-timestamps=true
+		show timestamps with directory listings
+	-index
+		enable identifier and full text search index
+		(no search box is shown if -index is not set)
+	-index_files=""
+		glob pattern specifying index files; if not empty,
+		the index is read from these files in sorted order
+	-index_throttle=0.75
+		index throttle value; a value of 0 means no time is allocated
+		to the indexer (the indexer will never finish), a value of 1.0
+		means that index creation is running at full throttle (other
+		goroutines may get no time while the index is built)
+	-links=true:
+		link identifiers to their declarations
+	-write_index=false
+		write index to a file; the file name must be specified with
+		-index_files
+	-maxresults=10000
+		maximum number of full text search results shown
+		(no full text index is built if maxresults <= 0)
+	-notes="BUG"
+		regular expression matching note markers to show
+		(e.g., "BUG|TODO", ".*")
+	-html
+		print HTML in command-line mode
+	-goroot=$GOROOT
+		Go root directory
+	-http=addr
+		HTTP service address (e.g., '127.0.0.1:6060' or just ':6060')
+	-server=addr
+		webserver address for command line searches
+	-analysis=type,pointer
+		comma-separated list of analyses to perform
+    		"type": display identifier resolution, type info, method sets,
+			'implements', and static callees
+		"pointer" display channel peers, callers and dynamic callees
+			(significantly slower)
+		See http://golang.org/lib/godoc/analysis/help.html for details.
+	-templates=""
+		directory containing alternate template files; if set,
+		the directory may provide alternative template files
+		for the files in $GOROOT/lib/godoc
+	-url=path
+		print to standard output the data that would be served by
+		an HTTP request for path
+	-zip=""
+		zip file providing the file system to serve; disabled if empty
+
+By default, godoc looks at the packages it finds via $GOROOT and $GOPATH (if set).
+This behavior can be altered by providing an alternative $GOROOT with the -goroot
+flag.
+
+When godoc runs as a web server and -index is set, a search index is maintained.
+The index is created at startup.
+
+The index contains both identifier and full text search information (searchable
+via regular expressions). The maximum number of full text search results shown
+can be set with the -maxresults flag; if set to 0, no full text results are
+shown, and only an identifier index but no full text search index is created.
+
+The presentation mode of web pages served by godoc can be controlled with the
+"m" URL parameter; it accepts a comma-separated list of flag names as value:
+
+	all	show documentation for all declarations, not just the exported ones
+	methods	show all embedded methods, not just those of unexported anonymous fields
+	src	show the original source code rather then the extracted documentation
+	text	present the page in textual (command-line) form rather than HTML
+	flat	present flat (not indented) directory listings using full paths
+
+For instance, http://golang.org/pkg/math/big/?m=all,text shows the documentation
+for all (not just the exported) declarations of package big, in textual form (as
+it would appear when using godoc from the command line: "godoc -src math/big .*").
+
+By default, godoc serves files from the file system of the underlying OS.
+Instead, a .zip file may be provided via the -zip flag, which contains
+the file system to serve. The file paths stored in the .zip file must use
+slash ('/') as path separator; and they must be unrooted. $GOROOT (or -goroot)
+must be set to the .zip file directory path containing the Go root directory.
+For instance, for a .zip file created by the command:
+
+	zip go.zip $HOME/go
+
+one may run godoc as follows:
+
+	godoc -http=:6060 -zip=go.zip -goroot=$HOME/go
+
+Godoc documentation is converted to HTML or to text using the go/doc package;
+see http://golang.org/pkg/go/doc/#ToHTML for the exact rules.
+Godoc also shows example code that is runnable by the testing package;
+see http://golang.org/pkg/testing/#hdr-Examples for the conventions.
+See "Godoc: documenting Go code" for how to write good comments for godoc:
+http://golang.org/doc/articles/godoc_documenting_go_code.html
+
+*/
+package main // import "golang.org/x/tools/cmd/godoc"
diff --git a/cmd/godoc/godoc_test.go b/cmd/godoc/godoc_test.go
new file mode 100644
index 0000000..a228fae
--- /dev/null
+++ b/cmd/godoc/godoc_test.go
@@ -0,0 +1,440 @@
+// Copyright 2013 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 main_test
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+)
+
+var godocTests = []struct {
+	args      []string
+	matches   []string // regular expressions
+	dontmatch []string // regular expressions
+}{
+	{
+		args: []string{"fmt"},
+		matches: []string{
+			`import "fmt"`,
+			`Package fmt implements formatted I/O`,
+		},
+	},
+	{
+		args: []string{"io", "WriteString"},
+		matches: []string{
+			`func WriteString\(`,
+			`WriteString writes the contents of the string s to w`,
+		},
+	},
+	{
+		args: []string{"nonexistingpkg"},
+		matches: []string{
+			`no such file or directory|does not exist|cannot find the file`,
+		},
+	},
+	{
+		args: []string{"fmt", "NonexistentSymbol"},
+		matches: []string{
+			`No match found\.`,
+		},
+	},
+	{
+		args: []string{"-src", "syscall", "Open"},
+		matches: []string{
+			`func Open\(`,
+		},
+		dontmatch: []string{
+			`No match found\.`,
+		},
+	},
+}
+
+// buildGodoc builds the godoc executable.
+// It returns its path, and a cleanup function.
+//
+// TODO(adonovan): opt: do this at most once, and do the cleanup
+// exactly once.  How though?  There's no atexit.
+func buildGodoc(t *testing.T) (bin string, cleanup func()) {
+	if runtime.GOARCH == "arm" {
+		t.Skip("skipping test on arm platforms; too slow")
+	}
+	tmp, err := ioutil.TempDir("", "godoc-regtest-")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		if cleanup == nil { // probably, go build failed.
+			os.RemoveAll(tmp)
+		}
+	}()
+
+	bin = filepath.Join(tmp, "godoc")
+	if runtime.GOOS == "windows" {
+		bin += ".exe"
+	}
+	cmd := exec.Command("go", "build", "-o", bin)
+	if err := cmd.Run(); err != nil {
+		t.Fatalf("Building godoc: %v", err)
+	}
+
+	return bin, func() { os.RemoveAll(tmp) }
+}
+
+// Basic regression test for godoc command-line tool.
+func TestCLI(t *testing.T) {
+	bin, cleanup := buildGodoc(t)
+	defer cleanup()
+	for _, test := range godocTests {
+		cmd := exec.Command(bin, test.args...)
+		cmd.Args[0] = "godoc"
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			t.Errorf("Running with args %#v: %v", test.args, err)
+			continue
+		}
+		for _, pat := range test.matches {
+			re := regexp.MustCompile(pat)
+			if !re.Match(out) {
+				t.Errorf("godoc %v =\n%s\nwanted /%v/", strings.Join(test.args, " "), out, pat)
+			}
+		}
+		for _, pat := range test.dontmatch {
+			re := regexp.MustCompile(pat)
+			if re.Match(out) {
+				t.Errorf("godoc %v =\n%s\ndid not want /%v/", strings.Join(test.args, " "), out, pat)
+			}
+		}
+	}
+}
+
+func serverAddress(t *testing.T) string {
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = net.Listen("tcp6", "[::1]:0")
+	}
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+	return ln.Addr().String()
+}
+
+func waitForServerReady(t *testing.T, addr string) {
+	waitForServer(t,
+		fmt.Sprintf("http://%v/", addr),
+		"The Go Programming Language",
+		5*time.Second)
+}
+
+func waitForSearchReady(t *testing.T, addr string) {
+	waitForServer(t,
+		fmt.Sprintf("http://%v/search?q=FALLTHROUGH", addr),
+		"The list of tokens.",
+		2*time.Minute)
+}
+
+const pollInterval = 200 * time.Millisecond
+
+func waitForServer(t *testing.T, url, match string, timeout time.Duration) {
+	// "health check" duplicated from x/tools/cmd/tipgodoc/tip.go
+	deadline := time.Now().Add(timeout)
+	for time.Now().Before(deadline) {
+		time.Sleep(pollInterval)
+		res, err := http.Get(url)
+		if err != nil {
+			continue
+		}
+		rbody, err := ioutil.ReadAll(res.Body)
+		res.Body.Close()
+		if err == nil && res.StatusCode == http.StatusOK &&
+			bytes.Contains(rbody, []byte(match)) {
+			return
+		}
+	}
+	t.Fatalf("Server failed to respond in %v", timeout)
+}
+
+func killAndWait(cmd *exec.Cmd) {
+	cmd.Process.Kill()
+	cmd.Wait()
+}
+
+// Basic integration test for godoc HTTP interface.
+func TestWeb(t *testing.T) {
+	testWeb(t, false)
+}
+
+// Basic integration test for godoc HTTP interface.
+func TestWebIndex(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in -short mode")
+	}
+	testWeb(t, true)
+}
+
+// Basic integration test for godoc HTTP interface.
+func testWeb(t *testing.T, withIndex bool) {
+	bin, cleanup := buildGodoc(t)
+	defer cleanup()
+	addr := serverAddress(t)
+	args := []string{fmt.Sprintf("-http=%s", addr)}
+	if withIndex {
+		args = append(args, "-index", "-index_interval=-1s")
+	}
+	cmd := exec.Command(bin, args...)
+	cmd.Stdout = os.Stderr
+	cmd.Stderr = os.Stderr
+	cmd.Args[0] = "godoc"
+	cmd.Env = godocEnv()
+	if err := cmd.Start(); err != nil {
+		t.Fatalf("failed to start godoc: %s", err)
+	}
+	defer killAndWait(cmd)
+
+	if withIndex {
+		waitForSearchReady(t, addr)
+	} else {
+		waitForServerReady(t, addr)
+	}
+
+	tests := []struct {
+		path      string
+		match     []string
+		dontmatch []string
+		needIndex bool
+	}{
+		{
+			path:  "/",
+			match: []string{"Go is an open source programming language"},
+		},
+		{
+			path:  "/pkg/fmt/",
+			match: []string{"Package fmt implements formatted I/O"},
+		},
+		{
+			path:  "/src/fmt/",
+			match: []string{"scan_test.go"},
+		},
+		{
+			path:  "/src/fmt/print.go",
+			match: []string{"// Println formats using"},
+		},
+		{
+			path: "/pkg",
+			match: []string{
+				"Standard library",
+				"Package fmt implements formatted I/O",
+			},
+			dontmatch: []string{
+				"internal/syscall",
+				"cmd/gc",
+			},
+		},
+		{
+			path: "/pkg/?m=all",
+			match: []string{
+				"Standard library",
+				"Package fmt implements formatted I/O",
+				"internal/syscall",
+			},
+			dontmatch: []string{
+				"cmd/gc",
+			},
+		},
+		{
+			path: "/search?q=notwithstanding",
+			match: []string{
+				"/src",
+			},
+			dontmatch: []string{
+				"/pkg/bootstrap",
+			},
+			needIndex: true,
+		},
+	}
+	for _, test := range tests {
+		if test.needIndex && !withIndex {
+			continue
+		}
+		url := fmt.Sprintf("http://%s%s", addr, test.path)
+		resp, err := http.Get(url)
+		if err != nil {
+			t.Errorf("GET %s failed: %s", url, err)
+			continue
+		}
+		body, err := ioutil.ReadAll(resp.Body)
+		resp.Body.Close()
+		if err != nil {
+			t.Errorf("GET %s: failed to read body: %s (response: %v)", url, err, resp)
+		}
+		isErr := false
+		for _, substr := range test.match {
+			if !bytes.Contains(body, []byte(substr)) {
+				t.Errorf("GET %s: wanted substring %q in body", url, substr)
+				isErr = true
+			}
+		}
+		for _, substr := range test.dontmatch {
+			if bytes.Contains(body, []byte(substr)) {
+				t.Errorf("GET %s: didn't want substring %q in body", url, substr)
+				isErr = true
+			}
+		}
+		if isErr {
+			t.Errorf("GET %s: got:\n%s", url, body)
+		}
+	}
+}
+
+// Basic integration test for godoc -analysis=type (via HTTP interface).
+func TestTypeAnalysis(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test on plan9 (issue #11974)") // see comment re: Plan 9 below
+	}
+
+	// Write a fake GOROOT/GOPATH.
+	tmpdir, err := ioutil.TempDir("", "godoc-analysis")
+	if err != nil {
+		t.Fatalf("ioutil.TempDir failed: %s", err)
+	}
+	defer os.RemoveAll(tmpdir)
+	for _, f := range []struct{ file, content string }{
+		{"goroot/src/lib/lib.go", `
+package lib
+type T struct{}
+const C = 3
+var V T
+func (T) F() int { return C }
+`},
+		{"gopath/src/app/main.go", `
+package main
+import "lib"
+func main() { print(lib.V) }
+`},
+	} {
+		file := filepath.Join(tmpdir, f.file)
+		if err := os.MkdirAll(filepath.Dir(file), 0755); err != nil {
+			t.Fatalf("MkdirAll(%s) failed: %s", filepath.Dir(file), err)
+		}
+		if err := ioutil.WriteFile(file, []byte(f.content), 0644); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	// Start the server.
+	bin, cleanup := buildGodoc(t)
+	defer cleanup()
+	addr := serverAddress(t)
+	cmd := exec.Command(bin, fmt.Sprintf("-http=%s", addr), "-analysis=type")
+	cmd.Env = append(cmd.Env, fmt.Sprintf("GOROOT=%s", filepath.Join(tmpdir, "goroot")))
+	cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%s", filepath.Join(tmpdir, "gopath")))
+	for _, e := range os.Environ() {
+		if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") {
+			continue
+		}
+		cmd.Env = append(cmd.Env, e)
+	}
+	cmd.Stdout = os.Stderr
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	cmd.Args[0] = "godoc"
+	if err := cmd.Start(); err != nil {
+		t.Fatalf("failed to start godoc: %s", err)
+	}
+	defer killAndWait(cmd)
+	waitForServerReady(t, addr)
+
+	// Wait for type analysis to complete.
+	reader := bufio.NewReader(stderr)
+	for {
+		s, err := reader.ReadString('\n') // on Plan 9 this fails
+		if err != nil {
+			t.Fatal(err)
+		}
+		fmt.Fprint(os.Stderr, s)
+		if strings.Contains(s, "Type analysis complete.") {
+			break
+		}
+	}
+	go io.Copy(os.Stderr, reader)
+
+	t0 := time.Now()
+
+	// Make an HTTP request and check for a regular expression match.
+	// The patterns are very crude checks that basic type information
+	// has been annotated onto the source view.
+tryagain:
+	for _, test := range []struct{ url, pattern string }{
+		{"/src/lib/lib.go", "L2.*package .*Package docs for lib.*/lib"},
+		{"/src/lib/lib.go", "L3.*type .*type info for T.*struct"},
+		{"/src/lib/lib.go", "L5.*var V .*type T struct"},
+		{"/src/lib/lib.go", "L6.*func .*type T struct.*T.*return .*const C untyped int.*C"},
+
+		{"/src/app/main.go", "L2.*package .*Package docs for app"},
+		{"/src/app/main.go", "L3.*import .*Package docs for lib.*lib"},
+		{"/src/app/main.go", "L4.*func main.*package lib.*lib.*var lib.V lib.T.*V"},
+	} {
+		url := fmt.Sprintf("http://%s%s", addr, test.url)
+		resp, err := http.Get(url)
+		if err != nil {
+			t.Errorf("GET %s failed: %s", url, err)
+			continue
+		}
+		body, err := ioutil.ReadAll(resp.Body)
+		resp.Body.Close()
+		if err != nil {
+			t.Errorf("GET %s: failed to read body: %s (response: %v)", url, err, resp)
+			continue
+		}
+
+		if !bytes.Contains(body, []byte("Static analysis features")) {
+			// Type analysis results usually become available within
+			// ~4ms after godoc startup (for this input on my machine).
+			if elapsed := time.Since(t0); elapsed > 500*time.Millisecond {
+				t.Fatalf("type analysis results still unavailable after %s", elapsed)
+			}
+			time.Sleep(10 * time.Millisecond)
+			goto tryagain
+		}
+
+		match, err := regexp.Match(test.pattern, body)
+		if err != nil {
+			t.Errorf("regexp.Match(%q) failed: %s", test.pattern, err)
+			continue
+		}
+		if !match {
+			// This is a really ugly failure message.
+			t.Errorf("GET %s: body doesn't match %q, got:\n%s",
+				url, test.pattern, string(body))
+		}
+	}
+}
+
+// godocEnv returns the process environment without the GOPATH variable.
+// (We don't want the indexer looking at the local workspace during tests.)
+func godocEnv() (env []string) {
+	for _, v := range os.Environ() {
+		if strings.HasPrefix(v, "GOPATH=") {
+			continue
+		}
+		env = append(env, v)
+	}
+	return
+}
diff --git a/cmd/godoc/handlers.go b/cmd/godoc/handlers.go
new file mode 100644
index 0000000..1f79d80
--- /dev/null
+++ b/cmd/godoc/handlers.go
@@ -0,0 +1,83 @@
+// 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 /doc/codewalk/ tree is synthesized from codewalk descriptions,
+// files named $GOROOT/doc/codewalk/*.xml.
+// For an example and a description of the format, see
+// http://golang.org/doc/codewalk/codewalk or run godoc -http=:6060
+// and see http://localhost:6060/doc/codewalk/codewalk .
+// That page is itself a codewalk; the source code for it is
+// $GOROOT/doc/codewalk/codewalk.xml.
+
+package main
+
+import (
+	"log"
+	"net/http"
+	"text/template"
+
+	"golang.org/x/tools/godoc"
+	"golang.org/x/tools/godoc/redirect"
+	"golang.org/x/tools/godoc/vfs"
+)
+
+var (
+	pres *godoc.Presentation
+	fs   = vfs.NameSpace{}
+)
+
+func registerHandlers(pres *godoc.Presentation) {
+	if pres == nil {
+		panic("nil Presentation")
+	}
+	http.HandleFunc("/doc/codewalk/", codewalk)
+	http.Handle("/doc/play/", pres.FileServer())
+	http.Handle("/robots.txt", pres.FileServer())
+	http.Handle("/", pres)
+	http.Handle("/pkg/C/", redirect.Handler("/cmd/cgo/"))
+	redirect.Register(nil)
+}
+
+func readTemplate(name string) *template.Template {
+	if pres == nil {
+		panic("no global Presentation set yet")
+	}
+	path := "lib/godoc/" + name
+
+	// use underlying file system fs to read the template file
+	// (cannot use template ParseFile functions directly)
+	data, err := vfs.ReadFile(fs, path)
+	if err != nil {
+		log.Fatal("readTemplate: ", err)
+	}
+	// be explicit with errors (for app engine use)
+	t, err := template.New(name).Funcs(pres.FuncMap()).Parse(string(data))
+	if err != nil {
+		log.Fatal("readTemplate: ", err)
+	}
+	return t
+}
+
+func readTemplates(p *godoc.Presentation, html bool) {
+	p.PackageText = readTemplate("package.txt")
+	p.SearchText = readTemplate("search.txt")
+
+	if html || p.HTMLMode {
+		codewalkHTML = readTemplate("codewalk.html")
+		codewalkdirHTML = readTemplate("codewalkdir.html")
+		p.CallGraphHTML = readTemplate("callgraph.html")
+		p.DirlistHTML = readTemplate("dirlist.html")
+		p.ErrorHTML = readTemplate("error.html")
+		p.ExampleHTML = readTemplate("example.html")
+		p.GodocHTML = readTemplate("godoc.html")
+		p.ImplementsHTML = readTemplate("implements.html")
+		p.MethodSetHTML = readTemplate("methodset.html")
+		p.PackageHTML = readTemplate("package.html")
+		p.SearchHTML = readTemplate("search.html")
+		p.SearchDocHTML = readTemplate("searchdoc.html")
+		p.SearchCodeHTML = readTemplate("searchcode.html")
+		p.SearchTxtHTML = readTemplate("searchtxt.html")
+		p.SearchDescXML = readTemplate("opensearch.xml")
+	}
+}
diff --git a/cmd/godoc/index.go b/cmd/godoc/index.go
new file mode 100644
index 0000000..f84b29a
--- /dev/null
+++ b/cmd/godoc/index.go
@@ -0,0 +1,11 @@
+// Copyright 2015 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 main
+
+import "strings"
+
+func indexDirectoryDefault(dir string) bool {
+	return dir != "/pkg" && !strings.HasPrefix(dir, "/pkg/")
+}
diff --git a/cmd/godoc/main.go b/cmd/godoc/main.go
new file mode 100644
index 0000000..3496013
--- /dev/null
+++ b/cmd/godoc/main.go
@@ -0,0 +1,329 @@
+// Copyright 2009 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.
+
+// godoc: Go Documentation Server
+
+// Web server tree:
+//
+//	http://godoc/		main landing page
+//	http://godoc/doc/	serve from $GOROOT/doc - spec, mem, etc.
+//	http://godoc/src/	serve files from $GOROOT/src; .go gets pretty-printed
+//	http://godoc/cmd/	serve documentation about commands
+//	http://godoc/pkg/	serve documentation about packages
+//				(idea is if you say import "compress/zlib", you go to
+//				http://godoc/pkg/compress/zlib)
+//
+// Command-line interface:
+//
+//	godoc packagepath [name ...]
+//
+//	godoc compress/zlib
+//		- prints doc for package compress/zlib
+//	godoc crypto/block Cipher NewCMAC
+//		- prints doc for Cipher and NewCMAC in package crypto/block
+
+// +build !appengine
+
+package main
+
+import (
+	"archive/zip"
+	_ "expvar" // to serve /debug/vars
+	"flag"
+	"fmt"
+	"go/build"
+	"log"
+	"net/http"
+	"net/http/httptest"
+	_ "net/http/pprof" // to serve /debug/pprof/*
+	"net/url"
+	"os"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+
+	"golang.org/x/tools/godoc"
+	"golang.org/x/tools/godoc/analysis"
+	"golang.org/x/tools/godoc/static"
+	"golang.org/x/tools/godoc/vfs"
+	"golang.org/x/tools/godoc/vfs/gatefs"
+	"golang.org/x/tools/godoc/vfs/mapfs"
+	"golang.org/x/tools/godoc/vfs/zipfs"
+)
+
+const (
+	defaultAddr = ":6060" // default webserver address
+	toolsPath   = "golang.org/x/tools/cmd/"
+)
+
+var (
+	// file system to serve
+	// (with e.g.: zip -r go.zip $GOROOT -i \*.go -i \*.html -i \*.css -i \*.js -i \*.txt -i \*.c -i \*.h -i \*.s -i \*.png -i \*.jpg -i \*.sh -i favicon.ico)
+	zipfile = flag.String("zip", "", "zip file providing the file system to serve; disabled if empty")
+
+	// file-based index
+	writeIndex = flag.Bool("write_index", false, "write index to a file; the file name must be specified with -index_files")
+
+	analysisFlag = flag.String("analysis", "", `comma-separated list of analyses to perform (supported: type, pointer). See http://golang.org/lib/godoc/analysis/help.html`)
+
+	// network
+	httpAddr   = flag.String("http", "", "HTTP service address (e.g., '"+defaultAddr+"')")
+	serverAddr = flag.String("server", "", "webserver address for command line searches")
+
+	// layout control
+	html    = flag.Bool("html", false, "print HTML in command-line mode")
+	srcMode = flag.Bool("src", false, "print (exported) source in command-line mode")
+	urlFlag = flag.String("url", "", "print HTML for named URL")
+
+	// command-line searches
+	query = flag.Bool("q", false, "arguments are considered search queries")
+
+	verbose = flag.Bool("v", false, "verbose mode")
+
+	// file system roots
+	// TODO(gri) consider the invariant that goroot always end in '/'
+	goroot = flag.String("goroot", runtime.GOROOT(), "Go root directory")
+
+	// layout control
+	tabWidth       = flag.Int("tabwidth", 4, "tab width")
+	showTimestamps = flag.Bool("timestamps", false, "show timestamps with directory listings")
+	templateDir    = flag.String("templates", "", "directory containing alternate template files")
+	showPlayground = flag.Bool("play", false, "enable playground in web interface")
+	showExamples   = flag.Bool("ex", false, "show examples in command line mode")
+	declLinks      = flag.Bool("links", true, "link identifiers to their declarations")
+
+	// search index
+	indexEnabled  = flag.Bool("index", false, "enable search index")
+	indexFiles    = flag.String("index_files", "", "glob pattern specifying index files; if not empty, the index is read from these files in sorted order")
+	indexInterval = flag.Duration("index_interval", 0, "interval of indexing; 0 for default (5m), negative to only index once at startup")
+	maxResults    = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
+	indexThrottle = flag.Float64("index_throttle", 0.75, "index throttle value; 0.0 = no time allocated, 1.0 = full throttle")
+
+	// source code notes
+	notesRx = flag.String("notes", "BUG", "regular expression matching note markers to show")
+)
+
+func usage() {
+	fmt.Fprintf(os.Stderr,
+		"usage: godoc package [name ...]\n"+
+			"	godoc -http="+defaultAddr+"\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func loggingHandler(h http.Handler) http.Handler {
+	return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+		log.Printf("%s\t%s", req.RemoteAddr, req.URL)
+		h.ServeHTTP(w, req)
+	})
+}
+
+func handleURLFlag() {
+	// Try up to 10 fetches, following redirects.
+	urlstr := *urlFlag
+	for i := 0; i < 10; i++ {
+		// Prepare request.
+		u, err := url.Parse(urlstr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		req := &http.Request{
+			URL: u,
+		}
+
+		// Invoke default HTTP handler to serve request
+		// to our buffering httpWriter.
+		w := httptest.NewRecorder()
+		http.DefaultServeMux.ServeHTTP(w, req)
+
+		// Return data, error, or follow redirect.
+		switch w.Code {
+		case 200: // ok
+			os.Stdout.Write(w.Body.Bytes())
+			return
+		case 301, 302, 303, 307: // redirect
+			redirect := w.HeaderMap.Get("Location")
+			if redirect == "" {
+				log.Fatalf("HTTP %d without Location header", w.Code)
+			}
+			urlstr = redirect
+		default:
+			log.Fatalf("HTTP error %d", w.Code)
+		}
+	}
+	log.Fatalf("too many redirects")
+}
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	playEnabled = *showPlayground
+
+	// Check usage: either server and no args, command line and args, or index creation mode
+	if (*httpAddr != "" || *urlFlag != "") != (flag.NArg() == 0) && !*writeIndex {
+		usage()
+	}
+
+	var fsGate chan bool
+	fsGate = make(chan bool, 20)
+
+	// Determine file system to use.
+	if *zipfile == "" {
+		// use file system of underlying OS
+		rootfs := gatefs.New(vfs.OS(*goroot), fsGate)
+		fs.Bind("/", rootfs, "/", vfs.BindReplace)
+	} else {
+		// use file system specified via .zip file (path separator must be '/')
+		rc, err := zip.OpenReader(*zipfile)
+		if err != nil {
+			log.Fatalf("%s: %s\n", *zipfile, err)
+		}
+		defer rc.Close() // be nice (e.g., -writeIndex mode)
+		fs.Bind("/", zipfs.New(rc, *zipfile), *goroot, vfs.BindReplace)
+	}
+	if *templateDir != "" {
+		fs.Bind("/lib/godoc", vfs.OS(*templateDir), "/", vfs.BindBefore)
+	} else {
+		fs.Bind("/lib/godoc", mapfs.New(static.Files), "/", vfs.BindReplace)
+	}
+
+	// Bind $GOPATH trees into Go root.
+	for _, p := range filepath.SplitList(build.Default.GOPATH) {
+		fs.Bind("/src", gatefs.New(vfs.OS(p), fsGate), "/src", vfs.BindAfter)
+	}
+
+	httpMode := *httpAddr != ""
+
+	var typeAnalysis, pointerAnalysis bool
+	if *analysisFlag != "" {
+		for _, a := range strings.Split(*analysisFlag, ",") {
+			switch a {
+			case "type":
+				typeAnalysis = true
+			case "pointer":
+				pointerAnalysis = true
+			default:
+				log.Fatalf("unknown analysis: %s", a)
+			}
+		}
+	}
+
+	corpus := godoc.NewCorpus(fs)
+	corpus.Verbose = *verbose
+	corpus.MaxResults = *maxResults
+	corpus.IndexEnabled = *indexEnabled && httpMode
+	if *maxResults == 0 {
+		corpus.IndexFullText = false
+	}
+	corpus.IndexFiles = *indexFiles
+	corpus.IndexDirectory = indexDirectoryDefault
+	corpus.IndexThrottle = *indexThrottle
+	corpus.IndexInterval = *indexInterval
+	if *writeIndex {
+		corpus.IndexThrottle = 1.0
+		corpus.IndexEnabled = true
+	}
+	if *writeIndex || httpMode || *urlFlag != "" {
+		if err := corpus.Init(); err != nil {
+			log.Fatal(err)
+		}
+	}
+
+	pres = godoc.NewPresentation(corpus)
+	pres.TabWidth = *tabWidth
+	pres.ShowTimestamps = *showTimestamps
+	pres.ShowPlayground = *showPlayground
+	pres.ShowExamples = *showExamples
+	pres.DeclLinks = *declLinks
+	pres.SrcMode = *srcMode
+	pres.HTMLMode = *html
+	if *notesRx != "" {
+		pres.NotesRx = regexp.MustCompile(*notesRx)
+	}
+
+	readTemplates(pres, httpMode || *urlFlag != "")
+	registerHandlers(pres)
+
+	if *writeIndex {
+		// Write search index and exit.
+		if *indexFiles == "" {
+			log.Fatal("no index file specified")
+		}
+
+		log.Println("initialize file systems")
+		*verbose = true // want to see what happens
+
+		corpus.UpdateIndex()
+
+		log.Println("writing index file", *indexFiles)
+		f, err := os.Create(*indexFiles)
+		if err != nil {
+			log.Fatal(err)
+		}
+		index, _ := corpus.CurrentIndex()
+		_, err = index.WriteTo(f)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		log.Println("done")
+		return
+	}
+
+	// Print content that would be served at the URL *urlFlag.
+	if *urlFlag != "" {
+		handleURLFlag()
+		return
+	}
+
+	if httpMode {
+		// HTTP server mode.
+		var handler http.Handler = http.DefaultServeMux
+		if *verbose {
+			log.Printf("Go Documentation Server")
+			log.Printf("version = %s", runtime.Version())
+			log.Printf("address = %s", *httpAddr)
+			log.Printf("goroot = %s", *goroot)
+			log.Printf("tabwidth = %d", *tabWidth)
+			switch {
+			case !*indexEnabled:
+				log.Print("search index disabled")
+			case *maxResults > 0:
+				log.Printf("full text index enabled (maxresults = %d)", *maxResults)
+			default:
+				log.Print("identifier search index enabled")
+			}
+			fs.Fprint(os.Stderr)
+			handler = loggingHandler(handler)
+		}
+
+		// Initialize search index.
+		if *indexEnabled {
+			go corpus.RunIndexer()
+		}
+
+		// Start type/pointer analysis.
+		if typeAnalysis || pointerAnalysis {
+			go analysis.Run(pointerAnalysis, &corpus.Analysis)
+		}
+
+		// Start http server.
+		if err := http.ListenAndServe(*httpAddr, handler); err != nil {
+			log.Fatalf("ListenAndServe %s: %v", *httpAddr, err)
+		}
+
+		return
+	}
+
+	if *query {
+		handleRemoteSearch()
+		return
+	}
+
+	if err := godoc.CommandLine(os.Stdout, fs, pres, flag.Args()); err != nil {
+		log.Print(err)
+	}
+}
diff --git a/cmd/godoc/play.go b/cmd/godoc/play.go
new file mode 100644
index 0000000..a56ffe2
--- /dev/null
+++ b/cmd/godoc/play.go
@@ -0,0 +1,44 @@
+// Copyright 2012 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 main
+
+import (
+	"encoding/json"
+	"fmt"
+	"go/format"
+	"net/http"
+
+	// This package registers "/compile" and "/share" handlers
+	// that redirect to the golang.org playground.
+	_ "golang.org/x/tools/playground"
+)
+
+func init() {
+	http.HandleFunc("/fmt", fmtHandler)
+}
+
+type fmtResponse struct {
+	Body  string
+	Error string
+}
+
+// fmtHandler takes a Go program in its "body" form value, formats it with
+// standard gofmt formatting, and writes a fmtResponse as a JSON object.
+func fmtHandler(w http.ResponseWriter, r *http.Request) {
+	resp := new(fmtResponse)
+	body, err := format.Source([]byte(r.FormValue("body")))
+	if err != nil {
+		resp.Error = err.Error()
+	} else {
+		resp.Body = string(body)
+	}
+	json.NewEncoder(w).Encode(resp)
+}
+
+// disabledHandler serves a 501 "Not Implemented" response.
+func disabledHandler(w http.ResponseWriter, r *http.Request) {
+	w.WriteHeader(http.StatusNotImplemented)
+	fmt.Fprint(w, "This functionality is not available via local godoc.")
+}
diff --git a/cmd/godoc/remotesearch.go b/cmd/godoc/remotesearch.go
new file mode 100644
index 0000000..f01d5c7
--- /dev/null
+++ b/cmd/godoc/remotesearch.go
@@ -0,0 +1,72 @@
+// Copyright 2009 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.
+
+// +build !appengine
+
+package main
+
+import (
+	"errors"
+	"flag"
+	"io"
+	"log"
+	"net/http"
+	"net/url"
+	"os"
+)
+
+func handleRemoteSearch() {
+	// Command-line queries.
+	for i := 0; i < flag.NArg(); i++ {
+		res, err := remoteSearch(flag.Arg(i))
+		if err != nil {
+			log.Fatalf("remoteSearch: %s", err)
+		}
+		io.Copy(os.Stdout, res.Body)
+	}
+	return
+}
+
+// remoteSearchURL returns the search URL for a given query as needed by
+// remoteSearch. If html is set, an html result is requested; otherwise
+// the result is in textual form.
+// Adjust this function as necessary if modeNames or FormValue parameters
+// change.
+func remoteSearchURL(query string, html bool) string {
+	s := "/search?m=text&q="
+	if html {
+		s = "/search?q="
+	}
+	return s + url.QueryEscape(query)
+}
+
+func remoteSearch(query string) (res *http.Response, err error) {
+	// list of addresses to try
+	var addrs []string
+	if *serverAddr != "" {
+		// explicit server address - only try this one
+		addrs = []string{*serverAddr}
+	} else {
+		addrs = []string{
+			defaultAddr,
+			"golang.org",
+		}
+	}
+
+	// remote search
+	search := remoteSearchURL(query, *html)
+	for _, addr := range addrs {
+		url := "http://" + addr + search
+		res, err = http.Get(url)
+		if err == nil && res.StatusCode == http.StatusOK {
+			break
+		}
+	}
+
+	if err == nil && res.StatusCode != http.StatusOK {
+		err = errors.New(res.Status)
+	}
+
+	return
+}
diff --git a/cmd/godoc/setup-godoc-app.bash b/cmd/godoc/setup-godoc-app.bash
new file mode 100755
index 0000000..9d82cd7
--- /dev/null
+++ b/cmd/godoc/setup-godoc-app.bash
@@ -0,0 +1,134 @@
+#!/usr/bin/env bash
+
+# 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.
+
+# This script creates a complete godoc app in $APPDIR.
+# It copies the cmd/godoc and src/go/... sources from GOROOT,
+# synthesizes an app.yaml file, and creates the .zip, index, and
+# configuration files.
+#
+# If an argument is provided it is assumed to be the app-engine godoc directory.
+# Without an argument, $APPDIR is used instead. If GOROOT is not set, "go env"
+# is consulted to find the $GOROOT.
+#
+# The script creates a .zip file representing the $GOROOT file system
+# and computes the correspondig search index files. These files are then
+# copied to $APPDIR. A corresponding godoc configuration file is created
+# in $APPDIR/appconfig.go.
+
+ZIPFILE=godoc.zip
+INDEXFILE=godoc.index
+SPLITFILES=index.split.
+GODOC=golang.org/x/tools/cmd/godoc
+CONFIGFILE=$GODOC/appconfig.go
+
+error() {
+	echo "error: $1"
+	exit 2
+}
+
+getArgs() {
+	if [ -z $APPENGINE_SDK ]; then
+		error "APPENGINE_SDK environment variable not set"
+	fi
+	if [ ! -x $APPENGINE_SDK/goapp ]; then
+		error "couldn't find goapp command in $APPENGINE_SDK"
+	fi
+	if [ -z $GOROOT ]; then
+		GOROOT=$(go env GOROOT)
+		echo "GOROOT not set explicitly, using go env value instead"
+	fi
+	if [ -z $APPDIR ]; then
+		if [ $# == 0 ]; then
+			error "APPDIR not set, and no argument provided"
+		fi
+		APPDIR=$1
+		echo "APPDIR not set, using argument instead"
+	fi
+
+	# safety checks
+	if [ ! -d $GOROOT ]; then
+		error "$GOROOT is not a directory"
+	fi
+	if [ -e $APPDIR ]; then
+		error "$APPDIR exists; check and remove it before trying again"
+	fi
+
+	# reporting
+	echo "GOROOT = $GOROOT"
+	echo "APPDIR = $APPDIR"
+}
+
+fetchGodoc() {
+	echo "*** Fetching godoc (if not already in GOPATH)"
+	unset GOBIN
+	go=$APPENGINE_SDK/goapp
+	$go get -d -tags appengine $GODOC
+	mkdir -p $APPDIR/$GODOC
+	cp $(find $($go list -f '{{.Dir}}' $GODOC) -type f -depth 1) $APPDIR/$GODOC/
+}
+
+makeAppYaml() {
+	echo "*** make $APPDIR/app.yaml"
+	cat > $APPDIR/app.yaml <<EOF
+application: godoc
+version: 1
+runtime: go
+api_version: go1.4beta
+
+handlers:
+- url: /.*
+  script: _go_app
+EOF
+}
+
+makeZipfile() {
+	echo "*** make $APPDIR/$ZIPFILE"
+	zip -q -r $APPDIR/$ZIPFILE $GOROOT/*
+}
+
+makeIndexfile() {
+	echo "*** make $APPDIR/$INDEXFILE"
+	GOPATH= godoc -write_index -index_files=$APPDIR/$INDEXFILE -zip=$APPDIR/$ZIPFILE
+}
+
+splitIndexfile() {
+	echo "*** split $APPDIR/$INDEXFILE"
+	split -b8m $APPDIR/$INDEXFILE $APPDIR/$SPLITFILES
+}
+
+makeConfigfile() {
+	echo "*** make $APPDIR/$CONFIGFILE"
+	cat > $APPDIR/$CONFIGFILE <<EOF
+package main
+
+// GENERATED FILE - DO NOT MODIFY BY HAND.
+// (generated by golang.org/x/tools/cmd/godoc/setup-godoc-app.bash)
+
+const (
+	// .zip filename
+	zipFilename = "$ZIPFILE"
+
+	// goroot directory in .zip file
+	zipGoroot = "$GOROOT"
+
+	// glob pattern describing search index files
+	// (if empty, the index is built at run-time)
+	indexFilenames = "$SPLITFILES*"
+)
+EOF
+}
+
+getArgs "$@"
+set -e
+mkdir $APPDIR
+fetchGodoc
+makeAppYaml
+makeZipfile
+makeIndexfile
+splitIndexfile
+makeConfigfile
+
+echo "*** setup complete"
diff --git a/cmd/godoc/x.go b/cmd/godoc/x.go
new file mode 100644
index 0000000..b4af41a
--- /dev/null
+++ b/cmd/godoc/x.go
@@ -0,0 +1,85 @@
+// Copyright 2013 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.
+
+// This file contains the handlers that serve go-import redirects for Go
+// sub-repositories. It specifies the mapping from import paths like
+// "golang.org/x/tools" to the actual repository locations.
+
+package main
+
+import (
+	"html/template"
+	"log"
+	"net/http"
+	"strings"
+)
+
+const xPrefix = "/x/"
+
+type xRepo struct {
+	URL, VCS string
+}
+
+var xMap = map[string]xRepo{
+	"codereview": {"https://code.google.com/p/go.codereview", "hg"},
+
+	"benchmarks": {"https://go.googlesource.com/benchmarks", "git"},
+	"blog":       {"https://go.googlesource.com/blog", "git"},
+	"build":      {"https://go.googlesource.com/build", "git"},
+	"crypto":     {"https://go.googlesource.com/crypto", "git"},
+	"debug":      {"https://go.googlesource.com/debug", "git"},
+	"exp":        {"https://go.googlesource.com/exp", "git"},
+	"image":      {"https://go.googlesource.com/image", "git"},
+	"mobile":     {"https://go.googlesource.com/mobile", "git"},
+	"net":        {"https://go.googlesource.com/net", "git"},
+	"oauth2":     {"https://go.googlesource.com/oauth2", "git"},
+	"playground": {"https://go.googlesource.com/playground", "git"},
+	"review":     {"https://go.googlesource.com/review", "git"},
+	"sys":        {"https://go.googlesource.com/sys", "git"},
+	"talks":      {"https://go.googlesource.com/talks", "git"},
+	"text":       {"https://go.googlesource.com/text", "git"},
+	"tools":      {"https://go.googlesource.com/tools", "git"},
+	"tour":       {"https://go.googlesource.com/tour", "git"},
+}
+
+func init() {
+	http.HandleFunc(xPrefix, xHandler)
+}
+
+func xHandler(w http.ResponseWriter, r *http.Request) {
+	head, tail := strings.TrimPrefix(r.URL.Path, xPrefix), ""
+	if i := strings.Index(head, "/"); i != -1 {
+		head, tail = head[:i], head[i:]
+	}
+	if head == "" {
+		http.Redirect(w, r, "https://godoc.org/-/subrepo", http.StatusTemporaryRedirect)
+		return
+	}
+	repo, ok := xMap[head]
+	if !ok {
+		http.NotFound(w, r)
+		return
+	}
+	data := struct {
+		Prefix, Head, Tail string
+		Repo               xRepo
+	}{xPrefix, head, tail, repo}
+	if err := xTemplate.Execute(w, data); err != nil {
+		log.Println("xHandler:", err)
+	}
+}
+
+var xTemplate = template.Must(template.New("x").Parse(`<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+<meta name="go-import" content="golang.org{{.Prefix}}{{.Head}} {{.Repo.VCS}} {{.Repo.URL}}">
+<meta name="go-source" content="golang.org{{.Prefix}}{{.Head}} https://github.com/golang/{{.Head}}/ https://github.com/golang/{{.Head}}/tree/master{/dir} https://github.com/golang/{{.Head}}/blob/master{/dir}/{file}#L{line}">
+<meta http-equiv="refresh" content="0; url=https://godoc.org/golang.org{{.Prefix}}{{.Head}}{{.Tail}}">
+</head>
+<body>
+Nothing to see here; <a href="https://godoc.org/golang.org{{.Prefix}}{{.Head}}{{.Tail}}">move along</a>.
+</body>
+</html>
+`))
diff --git a/cmd/goimports/doc.go b/cmd/goimports/doc.go
new file mode 100644
index 0000000..46b2b07
--- /dev/null
+++ b/cmd/goimports/doc.go
@@ -0,0 +1,33 @@
+/*
+
+Command goimports updates your Go import lines,
+adding missing ones and removing unreferenced ones.
+
+     $ go get golang.org/x/tools/cmd/goimports
+
+It's a drop-in replacement for your editor's gofmt-on-save hook.
+It has the same command-line interface as gofmt and formats
+your code in the same way.
+
+For emacs, make sure you have the latest go-mode.el:
+   https://github.com/dominikh/go-mode.el
+Then in your .emacs file:
+   (setq gofmt-command "goimports")
+   (add-to-list 'load-path "/home/you/somewhere/emacs/")
+   (require 'go-mode-load)
+   (add-hook 'before-save-hook 'gofmt-before-save)
+
+For vim, set "gofmt_command" to "goimports":
+    https://golang.org/change/39c724dd7f252
+    https://golang.org/wiki/IDEsAndTextEditorPlugins
+    etc
+
+For GoSublime, follow the steps described here:
+    http://michaelwhatcott.com/gosublime-goimports/
+
+For other editors, you probably know what to do.
+
+Happy hacking!
+
+*/
+package main // import "golang.org/x/tools/cmd/goimports"
diff --git a/cmd/goimports/goimports.go b/cmd/goimports/goimports.go
new file mode 100644
index 0000000..b0b7aa8
--- /dev/null
+++ b/cmd/goimports/goimports.go
@@ -0,0 +1,201 @@
+// Copyright 2013 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 main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/scanner"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+
+	"golang.org/x/tools/imports"
+)
+
+var (
+	// main operation modes
+	list   = flag.Bool("l", false, "list files whose formatting differs from goimport's")
+	write  = flag.Bool("w", false, "write result to (source) file instead of stdout")
+	doDiff = flag.Bool("d", false, "display diffs instead of rewriting files")
+
+	options = &imports.Options{
+		TabWidth:  8,
+		TabIndent: true,
+		Comments:  true,
+		Fragment:  true,
+	}
+	exitCode = 0
+)
+
+func init() {
+	flag.BoolVar(&options.AllErrors, "e", false, "report all errors (not just the first 10 on different lines)")
+}
+
+func report(err error) {
+	scanner.PrintError(os.Stderr, err)
+	exitCode = 2
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: goimports [flags] [path ...]\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func isGoFile(f os.FileInfo) bool {
+	// ignore non-Go files
+	name := f.Name()
+	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
+}
+
+func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
+	opt := options
+	if stdin {
+		nopt := *options
+		nopt.Fragment = true
+		opt = &nopt
+	}
+
+	if in == nil {
+		f, err := os.Open(filename)
+		if err != nil {
+			return err
+		}
+		defer f.Close()
+		in = f
+	}
+
+	src, err := ioutil.ReadAll(in)
+	if err != nil {
+		return err
+	}
+
+	res, err := imports.Process(filename, src, opt)
+	if err != nil {
+		return err
+	}
+
+	if !bytes.Equal(src, res) {
+		// formatting has changed
+		if *list {
+			fmt.Fprintln(out, filename)
+		}
+		if *write {
+			err = ioutil.WriteFile(filename, res, 0)
+			if err != nil {
+				return err
+			}
+		}
+		if *doDiff {
+			data, err := diff(src, res)
+			if err != nil {
+				return fmt.Errorf("computing diff: %s", err)
+			}
+			fmt.Printf("diff %s gofmt/%s\n", filename, filename)
+			out.Write(data)
+		}
+	}
+
+	if !*list && !*write && !*doDiff {
+		_, err = out.Write(res)
+	}
+
+	return err
+}
+
+func visitFile(path string, f os.FileInfo, err error) error {
+	if err == nil && isGoFile(f) {
+		err = processFile(path, nil, os.Stdout, false)
+	}
+	if err != nil {
+		report(err)
+	}
+	return nil
+}
+
+func walkDir(path string) {
+	filepath.Walk(path, visitFile)
+}
+
+func main() {
+	runtime.GOMAXPROCS(runtime.NumCPU())
+
+	// call gofmtMain in a separate function
+	// so that it can use defer and have them
+	// run before the exit.
+	gofmtMain()
+	os.Exit(exitCode)
+}
+
+// parseFlags parses command line flags and returns the paths to process.
+// It's a var so that custom implementations can replace it in other files.
+var parseFlags = func() []string {
+	flag.Parse()
+	return flag.Args()
+}
+
+func gofmtMain() {
+	flag.Usage = usage
+	paths := parseFlags()
+
+	if options.TabWidth < 0 {
+		fmt.Fprintf(os.Stderr, "negative tabwidth %d\n", options.TabWidth)
+		exitCode = 2
+		return
+	}
+
+	if len(paths) == 0 {
+		if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
+			report(err)
+		}
+		return
+	}
+
+	for _, path := range paths {
+		switch dir, err := os.Stat(path); {
+		case err != nil:
+			report(err)
+		case dir.IsDir():
+			walkDir(path)
+		default:
+			if err := processFile(path, nil, os.Stdout, false); err != nil {
+				report(err)
+			}
+		}
+	}
+}
+
+func diff(b1, b2 []byte) (data []byte, err error) {
+	f1, err := ioutil.TempFile("", "gofmt")
+	if err != nil {
+		return
+	}
+	defer os.Remove(f1.Name())
+	defer f1.Close()
+
+	f2, err := ioutil.TempFile("", "gofmt")
+	if err != nil {
+		return
+	}
+	defer os.Remove(f2.Name())
+	defer f2.Close()
+
+	f1.Write(b1)
+	f2.Write(b2)
+
+	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+	if len(data) > 0 {
+		// diff exits with a non-zero status when the files don't match.
+		// Ignore that failure as long as we get output.
+		err = nil
+	}
+	return
+}
diff --git a/cmd/gomvpkg/main.go b/cmd/gomvpkg/main.go
new file mode 100644
index 0000000..959b84e
--- /dev/null
+++ b/cmd/gomvpkg/main.go
@@ -0,0 +1,94 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// licence that can be found in the LICENSE file.
+
+// The gomvpkg command moves go packages, updating import declarations.
+// See the -help message or Usage constant for details.
+package main
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"os"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/refactor/rename"
+)
+
+var (
+	fromFlag     = flag.String("from", "", "Import path of package to be moved")
+	toFlag       = flag.String("to", "", "Destination import path for package")
+	vcsMvCmdFlag = flag.String("vcs_mv_cmd", "", `A template for the version control system's "move directory" command, e.g. "git mv {{.Src}} {{.Dst}}`)
+	helpFlag     = flag.Bool("help", false, "show usage message")
+)
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const Usage = `gomvpkg: moves a package, updating import declarations
+
+Usage:
+
+ gomvpkg -from <path> -to <path> [-vcs_mv_cmd <template>]
+
+Flags:
+
+-from        specifies the import path of the package to be moved
+
+-to          specifies the destination import path
+
+-vcs_mv_cmd  specifies a shell command to inform the version control system of a
+             directory move.  The argument is a template using the syntax of the
+             text/template package. It has two fields: Src and Dst, the absolute
+             paths of the directories.
+
+             For example: "git mv {{.Src}} {{.Dst}}"
+
+gomvpkg determines the set of packages that might be affected, including all
+packages importing the 'from' package and any of its subpackages. It will move
+the 'from' package and all its subpackages to the destination path and update all
+imports of those packages to point to its new import path.
+
+gomvpkg rejects moves in which a package already exists at the destination import
+path, or in which a directory already exists at the location the package would be
+moved to.
+
+gomvpkg will not always be able to rename imports when a package's name is changed.
+Import statements may want further cleanup.
+
+gomvpkg's behavior is not defined if any of the packages to be moved are
+imported using dot imports.
+
+Examples:
+
+% gomvpkg -from myproject/foo -to myproject/bar
+
+  Move the package with import path "myproject/foo" to the new path
+  "myproject/bar".
+
+% gomvpkg -from myproject/foo -to myproject/bar -vcs_mv_cmd "git mv {{.Src}} {{.Dst}}"
+
+  Move the package with import path "myproject/foo" to the new path
+  "myproject/bar" using "git mv" to execute the directory move.
+`
+
+func main() {
+	flag.Parse()
+
+	if len(flag.Args()) > 0 {
+		fmt.Fprintln(os.Stderr, "gomvpkg: surplus arguments.")
+		os.Exit(1)
+	}
+
+	if *helpFlag || *fromFlag == "" || *toFlag == "" {
+		fmt.Println(Usage)
+		return
+	}
+
+	if err := rename.Move(&build.Default, *fromFlag, *toFlag, *vcsMvCmdFlag); err != nil {
+		fmt.Fprintf(os.Stderr, "gomvpkg: %s.\n", err)
+		os.Exit(1)
+	}
+}
diff --git a/cmd/gorename/main.go b/cmd/gorename/main.go
new file mode 100644
index 0000000..922dc0c
--- /dev/null
+++ b/cmd/gorename/main.go
@@ -0,0 +1,63 @@
+// The gorename command performs precise type-safe renaming of
+// identifiers in Go source code.
+//
+// Run with -help for usage information, or view the Usage constant in
+// package golang.org/x/tools/refactor/rename, which contains most of
+// the implementation.
+//
+package main // import "golang.org/x/tools/cmd/gorename"
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"os"
+	"runtime"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/refactor/rename"
+)
+
+var (
+	offsetFlag = flag.String("offset", "", "file and byte offset of identifier to be renamed, e.g. 'file.go:#123'.  For use by editors.")
+	fromFlag   = flag.String("from", "", "identifier to be renamed; see -help for formats")
+	toFlag     = flag.String("to", "", "new name for identifier")
+	helpFlag   = flag.Bool("help", false, "show usage message")
+)
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+	flag.BoolVar(&rename.Force, "force", false, "proceed, even if conflicts were reported")
+	flag.BoolVar(&rename.DryRun, "dryrun", false, "show the change, but do not apply it")
+	flag.BoolVar(&rename.Verbose, "v", false, "print verbose information")
+
+	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
+	// For small machines, use at least 4 threads.
+	if os.Getenv("GOMAXPROCS") == "" {
+		n := runtime.NumCPU()
+		if n < 4 {
+			n = 4
+		}
+		runtime.GOMAXPROCS(n)
+	}
+}
+
+func main() {
+	flag.Parse()
+	if len(flag.Args()) > 0 {
+		fmt.Fprintln(os.Stderr, "gorename: surplus arguments.")
+		os.Exit(1)
+	}
+
+	if *helpFlag || (*offsetFlag == "" && *fromFlag == "" && *toFlag == "") {
+		fmt.Println(rename.Usage)
+		return
+	}
+
+	if err := rename.Main(&build.Default, *offsetFlag, *fromFlag, *toFlag); err != nil {
+		if err != rename.ConflictError {
+			fmt.Fprintf(os.Stderr, "gorename: %s\n", err)
+		}
+		os.Exit(1)
+	}
+}
diff --git a/cmd/gotype/doc.go b/cmd/gotype/doc.go
new file mode 100644
index 0000000..ea0b2b1
--- /dev/null
+++ b/cmd/gotype/doc.go
@@ -0,0 +1,62 @@
+// 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.
+
+/*
+The gotype command does syntactic and semantic analysis of Go files
+and packages like the front-end of a Go compiler. Errors are reported
+if the analysis fails; otherwise gotype is quiet (unless -v is set).
+
+Without a list of paths, gotype reads from standard input, which
+must provide a single Go source file defining a complete package.
+
+If a single path is specified that is a directory, gotype checks
+the Go files in that directory; they must all belong to the same
+package.
+
+Otherwise, each path must be the filename of Go file belonging to
+the same package.
+
+Usage:
+	gotype [flags] [path...]
+
+The flags are:
+	-a
+		use all (incl. _test.go) files when processing a directory
+	-e
+		report all errors (not just the first 10)
+	-v
+		verbose mode
+	-gccgo
+		use gccimporter instead of gcimporter
+
+Debugging flags:
+	-seq
+		parse sequentially, rather than in parallel
+	-ast
+		print AST (forces -seq)
+	-trace
+		print parse trace (forces -seq)
+	-comments
+		parse comments (ignored unless -ast or -trace is provided)
+
+Examples:
+
+To check the files a.go, b.go, and c.go:
+
+	gotype a.go b.go c.go
+
+To check an entire package in the directory dir and print the processed files:
+
+	gotype -v dir
+
+To check an entire package including tests in the local directory:
+
+	gotype -a .
+
+To verify the output of a pipe:
+
+	echo "package foo" | gotype
+
+*/
+package main // import "golang.org/x/tools/cmd/gotype"
diff --git a/cmd/gotype/gotype.go b/cmd/gotype/gotype.go
new file mode 100644
index 0000000..4a5c7de
--- /dev/null
+++ b/cmd/gotype/gotype.go
@@ -0,0 +1,262 @@
+// 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 main
+
+import (
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/scanner"
+	"go/token"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"time"
+
+	"golang.org/x/tools/go/gccgoimporter"
+	_ "golang.org/x/tools/go/gcimporter"
+	"golang.org/x/tools/go/types"
+)
+
+var (
+	// main operation modes
+	allFiles  = flag.Bool("a", false, "use all (incl. _test.go) files when processing a directory")
+	allErrors = flag.Bool("e", false, "report all errors (not just the first 10)")
+	verbose   = flag.Bool("v", false, "verbose mode")
+	gccgo     = flag.Bool("gccgo", false, "use gccgoimporter instead of gcimporter")
+
+	// debugging support
+	sequential    = flag.Bool("seq", false, "parse sequentially, rather than in parallel")
+	printAST      = flag.Bool("ast", false, "print AST (forces -seq)")
+	printTrace    = flag.Bool("trace", false, "print parse trace (forces -seq)")
+	parseComments = flag.Bool("comments", false, "parse comments (ignored unless -ast or -trace is provided)")
+)
+
+var (
+	fset       = token.NewFileSet()
+	errorCount = 0
+	parserMode parser.Mode
+	sizes      types.Sizes
+)
+
+func initParserMode() {
+	if *allErrors {
+		parserMode |= parser.AllErrors
+	}
+	if *printTrace {
+		parserMode |= parser.Trace
+	}
+	if *parseComments && (*printAST || *printTrace) {
+		parserMode |= parser.ParseComments
+	}
+}
+
+func initSizes() {
+	wordSize := 8
+	maxAlign := 8
+	switch build.Default.GOARCH {
+	case "386", "arm":
+		wordSize = 4
+		maxAlign = 4
+		// add more cases as needed
+	}
+	sizes = &types.StdSizes{WordSize: int64(wordSize), MaxAlign: int64(maxAlign)}
+}
+
+func usage() {
+	fmt.Fprintln(os.Stderr, "usage: gotype [flags] [path ...]")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func report(err error) {
+	scanner.PrintError(os.Stderr, err)
+	if list, ok := err.(scanner.ErrorList); ok {
+		errorCount += len(list)
+		return
+	}
+	errorCount++
+}
+
+// parse may be called concurrently
+func parse(filename string, src interface{}) (*ast.File, error) {
+	if *verbose {
+		fmt.Println(filename)
+	}
+	file, err := parser.ParseFile(fset, filename, src, parserMode) // ok to access fset concurrently
+	if *printAST {
+		ast.Print(fset, file)
+	}
+	return file, err
+}
+
+func parseStdin() (*ast.File, error) {
+	src, err := ioutil.ReadAll(os.Stdin)
+	if err != nil {
+		return nil, err
+	}
+	return parse("<standard input>", src)
+}
+
+func parseFiles(filenames []string) ([]*ast.File, error) {
+	files := make([]*ast.File, len(filenames))
+
+	if *sequential {
+		for i, filename := range filenames {
+			var err error
+			files[i], err = parse(filename, nil)
+			if err != nil {
+				return nil, err // leave unfinished goroutines hanging
+			}
+		}
+	} else {
+		type parseResult struct {
+			file *ast.File
+			err  error
+		}
+
+		out := make(chan parseResult)
+		for _, filename := range filenames {
+			go func(filename string) {
+				file, err := parse(filename, nil)
+				out <- parseResult{file, err}
+			}(filename)
+		}
+
+		for i := range filenames {
+			res := <-out
+			if res.err != nil {
+				return nil, res.err // leave unfinished goroutines hanging
+			}
+			files[i] = res.file
+		}
+	}
+
+	return files, nil
+}
+
+func parseDir(dirname string) ([]*ast.File, error) {
+	ctxt := build.Default
+	pkginfo, err := ctxt.ImportDir(dirname, 0)
+	if _, nogo := err.(*build.NoGoError); err != nil && !nogo {
+		return nil, err
+	}
+	filenames := append(pkginfo.GoFiles, pkginfo.CgoFiles...)
+	if *allFiles {
+		filenames = append(filenames, pkginfo.TestGoFiles...)
+	}
+
+	// complete file names
+	for i, filename := range filenames {
+		filenames[i] = filepath.Join(dirname, filename)
+	}
+
+	return parseFiles(filenames)
+}
+
+func getPkgFiles(args []string) ([]*ast.File, error) {
+	if len(args) == 0 {
+		// stdin
+		file, err := parseStdin()
+		if err != nil {
+			return nil, err
+		}
+		return []*ast.File{file}, nil
+	}
+
+	if len(args) == 1 {
+		// possibly a directory
+		path := args[0]
+		info, err := os.Stat(path)
+		if err != nil {
+			return nil, err
+		}
+		if info.IsDir() {
+			return parseDir(path)
+		}
+	}
+
+	// list of files
+	return parseFiles(args)
+}
+
+func checkPkgFiles(files []*ast.File) {
+	type bailout struct{}
+	conf := types.Config{
+		FakeImportC: true,
+		Error: func(err error) {
+			if !*allErrors && errorCount >= 10 {
+				panic(bailout{})
+			}
+			report(err)
+		},
+		Sizes: sizes,
+	}
+	if *gccgo {
+		var inst gccgoimporter.GccgoInstallation
+		inst.InitFromDriver("gccgo")
+		conf.Import = inst.GetImporter(nil, nil)
+	}
+
+	defer func() {
+		switch p := recover().(type) {
+		case nil, bailout:
+			// normal return or early exit
+		default:
+			// re-panic
+			panic(p)
+		}
+	}()
+
+	const path = "pkg" // any non-empty string will do for now
+	conf.Check(path, fset, files, nil)
+}
+
+func printStats(d time.Duration) {
+	fileCount := 0
+	lineCount := 0
+	fset.Iterate(func(f *token.File) bool {
+		fileCount++
+		lineCount += f.LineCount()
+		return true
+	})
+
+	fmt.Printf(
+		"%s (%d files, %d lines, %d lines/s)\n",
+		d, fileCount, lineCount, int64(float64(lineCount)/d.Seconds()),
+	)
+}
+
+func main() {
+	runtime.GOMAXPROCS(runtime.NumCPU()) // remove this once runtime is smarter
+
+	flag.Usage = usage
+	flag.Parse()
+	if *printAST || *printTrace {
+		*sequential = true
+	}
+	initParserMode()
+	initSizes()
+
+	start := time.Now()
+
+	files, err := getPkgFiles(flag.Args())
+	if err != nil {
+		report(err)
+		os.Exit(2)
+	}
+
+	checkPkgFiles(files)
+	if errorCount > 0 {
+		os.Exit(2)
+	}
+
+	if *verbose {
+		printStats(time.Since(start))
+	}
+}
diff --git a/cmd/html2article/conv.go b/cmd/html2article/conv.go
new file mode 100644
index 0000000..d3267d7
--- /dev/null
+++ b/cmd/html2article/conv.go
@@ -0,0 +1,366 @@
+// Copyright 2013 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.
+
+// This program takes an HTML file and outputs a corresponding article file in
+// present format. See: golang.org/x/tools/present
+package main // import "golang.org/x/tools/cmd/html2article"
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"net/url"
+	"os"
+	"regexp"
+	"strings"
+
+	"golang.org/x/net/html"
+	"golang.org/x/net/html/atom"
+)
+
+func main() {
+	flag.Parse()
+
+	err := convert(os.Stdout, os.Stdin)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func convert(w io.Writer, r io.Reader) error {
+	root, err := html.Parse(r)
+	if err != nil {
+		return err
+	}
+
+	style := find(root, isTag(atom.Style))
+	parseStyles(style)
+
+	body := find(root, isTag(atom.Body))
+	if body == nil {
+		return errors.New("couldn't find body")
+	}
+	article := limitNewlineRuns(makeHeadings(strings.TrimSpace(text(body))))
+	_, err = fmt.Fprintf(w, "Title\n\n%s", article)
+	return err
+}
+
+type Style string
+
+const (
+	Bold   Style = "*"
+	Italic Style = "_"
+	Code   Style = "`"
+)
+
+var cssRules = make(map[string]Style)
+
+func parseStyles(style *html.Node) {
+	if style == nil || style.FirstChild == nil {
+		log.Println("couldn't find styles")
+		return
+	}
+	s := bufio.NewScanner(strings.NewReader(style.FirstChild.Data))
+
+	findRule := func(b []byte, atEOF bool) (advance int, token []byte, err error) {
+		if i := bytes.Index(b, []byte("{")); i >= 0 {
+			token = bytes.TrimSpace(b[:i])
+			advance = i
+		}
+		return
+	}
+	findBody := func(b []byte, atEOF bool) (advance int, token []byte, err error) {
+		if len(b) == 0 {
+			return
+		}
+		if b[0] != '{' {
+			err = fmt.Errorf("expected {, got %c", b[0])
+			return
+		}
+		if i := bytes.Index(b, []byte("}")); i < 0 {
+			err = fmt.Errorf("can't find closing }")
+			return
+		} else {
+			token = b[1:i]
+			advance = i + 1
+		}
+		return
+	}
+
+	s.Split(findRule)
+	for s.Scan() {
+		rule := s.Text()
+		s.Split(findBody)
+		if !s.Scan() {
+			break
+		}
+		b := strings.ToLower(s.Text())
+		switch {
+		case strings.Contains(b, "italic"):
+			cssRules[rule] = Italic
+		case strings.Contains(b, "bold"):
+			cssRules[rule] = Bold
+		case strings.Contains(b, "Consolas") || strings.Contains(b, "Courier New"):
+			cssRules[rule] = Code
+		}
+		s.Split(findRule)
+	}
+	if err := s.Err(); err != nil {
+		log.Println(err)
+	}
+}
+
+var newlineRun = regexp.MustCompile(`\n\n+`)
+
+func limitNewlineRuns(s string) string {
+	return newlineRun.ReplaceAllString(s, "\n\n")
+}
+
+func makeHeadings(body string) string {
+	buf := new(bytes.Buffer)
+	lines := strings.Split(body, "\n")
+	for i, s := range lines {
+		if i == 0 && !isBoldTitle(s) {
+			buf.WriteString("* Introduction\n\n")
+		}
+		if isBoldTitle(s) {
+			s = strings.TrimSpace(strings.Replace(s, "*", " ", -1))
+			s = "* " + s
+		}
+		buf.WriteString(s)
+		buf.WriteByte('\n')
+	}
+	return buf.String()
+}
+
+func isBoldTitle(s string) bool {
+	return !strings.Contains(s, " ") &&
+		strings.HasPrefix(s, "*") &&
+		strings.HasSuffix(s, "*")
+}
+
+func indent(buf *bytes.Buffer, s string) {
+	for _, l := range strings.Split(s, "\n") {
+		if l != "" {
+			buf.WriteByte('\t')
+			buf.WriteString(l)
+		}
+		buf.WriteByte('\n')
+	}
+}
+
+func unwrap(buf *bytes.Buffer, s string) {
+	var cont bool
+	for _, l := range strings.Split(s, "\n") {
+		l = strings.TrimSpace(l)
+		if len(l) == 0 {
+			if cont {
+				buf.WriteByte('\n')
+				buf.WriteByte('\n')
+			}
+			cont = false
+		} else {
+			if cont {
+				buf.WriteByte(' ')
+			}
+			buf.WriteString(l)
+			cont = true
+		}
+	}
+}
+
+func text(n *html.Node) string {
+	var buf bytes.Buffer
+	walk(n, func(n *html.Node) bool {
+		switch n.Type {
+		case html.TextNode:
+			buf.WriteString(n.Data)
+			return false
+		case html.ElementNode:
+			// no-op
+		default:
+			return true
+		}
+		a := n.DataAtom
+		if a == atom.Span {
+			switch {
+			case hasStyle(Code)(n):
+				a = atom.Code
+			case hasStyle(Bold)(n):
+				a = atom.B
+			case hasStyle(Italic)(n):
+				a = atom.I
+			}
+		}
+		switch a {
+		case atom.Br:
+			buf.WriteByte('\n')
+		case atom.P:
+			unwrap(&buf, childText(n))
+			buf.WriteString("\n\n")
+		case atom.Li:
+			buf.WriteString("- ")
+			unwrap(&buf, childText(n))
+			buf.WriteByte('\n')
+		case atom.Pre:
+			indent(&buf, childText(n))
+			buf.WriteByte('\n')
+		case atom.A:
+			href, text := attr(n, "href"), childText(n)
+			// Skip links with no text.
+			if strings.TrimSpace(text) == "" {
+				break
+			}
+			// Don't emit empty links.
+			if strings.TrimSpace(href) == "" {
+				buf.WriteString(text)
+				break
+			}
+			// Use original url for Google Docs redirections.
+			if u, err := url.Parse(href); err != nil {
+				log.Printf("parsing url %q: %v", href, err)
+			} else if u.Host == "www.google.com" && u.Path == "/url" {
+				href = u.Query().Get("q")
+			}
+			fmt.Fprintf(&buf, "[[%s][%s]]", href, text)
+		case atom.Code:
+			buf.WriteString(highlight(n, "`"))
+		case atom.B:
+			buf.WriteString(highlight(n, "*"))
+		case atom.I:
+			buf.WriteString(highlight(n, "_"))
+		case atom.Img:
+			src := attr(n, "src")
+			fmt.Fprintf(&buf, ".image %s\n", src)
+		case atom.Iframe:
+			src, w, h := attr(n, "src"), attr(n, "width"), attr(n, "height")
+			fmt.Fprintf(&buf, "\n.iframe %s %s %s\n", src, h, w)
+		case atom.Param:
+			if attr(n, "name") == "movie" {
+				// Old style YouTube embed.
+				u := attr(n, "value")
+				u = strings.Replace(u, "/v/", "/embed/", 1)
+				if i := strings.Index(u, "&"); i >= 0 {
+					u = u[:i]
+				}
+				fmt.Fprintf(&buf, "\n.iframe %s 540 304\n", u)
+			}
+		case atom.Title:
+		default:
+			return true
+		}
+		return false
+	})
+	return buf.String()
+}
+
+func childText(node *html.Node) string {
+	var buf bytes.Buffer
+	for n := node.FirstChild; n != nil; n = n.NextSibling {
+		fmt.Fprint(&buf, text(n))
+	}
+	return buf.String()
+}
+
+func highlight(node *html.Node, char string) string {
+	t := strings.Replace(childText(node), " ", char, -1)
+	return fmt.Sprintf("%s%s%s", char, t, char)
+}
+
+type selector func(*html.Node) bool
+
+func isTag(a atom.Atom) selector {
+	return func(n *html.Node) bool {
+		return n.DataAtom == a
+	}
+}
+
+func hasClass(name string) selector {
+	return func(n *html.Node) bool {
+		for _, a := range n.Attr {
+			if a.Key == "class" {
+				for _, c := range strings.Fields(a.Val) {
+					if c == name {
+						return true
+					}
+				}
+			}
+		}
+		return false
+	}
+}
+
+func hasStyle(s Style) selector {
+	return func(n *html.Node) bool {
+		for rule, s2 := range cssRules {
+			if s2 != s {
+				continue
+			}
+			if strings.HasPrefix(rule, ".") && hasClass(rule[1:])(n) {
+				return true
+			}
+			if n.DataAtom.String() == rule {
+				return true
+			}
+		}
+		return false
+	}
+}
+
+func hasAttr(key, val string) selector {
+	return func(n *html.Node) bool {
+		for _, a := range n.Attr {
+			if a.Key == key && a.Val == val {
+				return true
+			}
+		}
+		return false
+	}
+}
+
+func attr(node *html.Node, key string) (value string) {
+	for _, attr := range node.Attr {
+		if attr.Key == key {
+			return attr.Val
+		}
+	}
+	return ""
+}
+
+func findAll(node *html.Node, fn selector) (nodes []*html.Node) {
+	walk(node, func(n *html.Node) bool {
+		if fn(n) {
+			nodes = append(nodes, n)
+		}
+		return true
+	})
+	return
+}
+
+func find(n *html.Node, fn selector) *html.Node {
+	var result *html.Node
+	walk(n, func(n *html.Node) bool {
+		if result != nil {
+			return false
+		}
+		if fn(n) {
+			result = n
+			return false
+		}
+		return true
+	})
+	return result
+}
+
+func walk(n *html.Node, fn selector) {
+	if fn(n) {
+		for c := n.FirstChild; c != nil; c = c.NextSibling {
+			walk(c, fn)
+		}
+	}
+}
diff --git a/cmd/oracle/emacs-test.bash b/cmd/oracle/emacs-test.bash
new file mode 100755
index 0000000..8c39091
--- /dev/null
+++ b/cmd/oracle/emacs-test.bash
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# Simple test of Go oracle/Emacs integration.
+# Requires that GOROOT and GOPATH are set.
+# Side effect: builds and installs oracle in $GOROOT.
+
+set -eu
+
+[ -z "$GOROOT" ] && { echo "Error: GOROOT is unset." >&2; exit 1; }
+[ -z "$GOPATH" ] && { echo "Error: GOPATH is unset." >&2; exit 1; }
+
+log=/tmp/$(basename $0)-$$.log
+thisdir=$(dirname $0)
+
+function die() {
+  echo "Error: $@."
+  cat $log
+  exit 1
+} >&2
+
+trap "rm -f $log" EXIT
+
+# Build and install oracle.
+go get golang.org/x/tools/cmd/oracle || die "'go get' failed"
+mv -f $GOPATH/bin/oracle $GOROOT/bin/
+$GOROOT/bin/oracle >$log 2>&1 || true # (prints usage and exits 1)
+grep -q "Run.*help" $log || die "$GOROOT/bin/oracle not installed"
+
+
+# Run Emacs, set the scope to the oracle tool itself,
+# load ./main.go, and describe the "fmt" import.
+emacs --batch --no-splash --no-window-system --no-init \
+    --load $GOROOT/misc/emacs/go-mode.el \
+    --load $thisdir/oracle.el \
+    --eval '
+(progn
+  (setq go-oracle-scope "golang.org/x/tools/cmd/oracle")
+  (find-file "'$thisdir'/main.go")
+  (search-forward "\"fmt\"")
+  (backward-char)
+  (go-oracle-describe)
+  (princ (with-current-buffer "*go-oracle*"
+                              (buffer-substring-no-properties (point-min) (point-max))))
+  (kill-emacs 0))
+' main.go >$log 2>&1 || die "emacs command failed"
+
+# Check that Println is mentioned.
+grep -q "fmt/print.go.*func  Println" $log || die "didn't find expected lines in log; got:"
+
+echo "PASS"
diff --git a/cmd/oracle/main.go b/cmd/oracle/main.go
new file mode 100644
index 0000000..a7a1661
--- /dev/null
+++ b/cmd/oracle/main.go
@@ -0,0 +1,204 @@
+// Copyright 2013 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.
+
+// oracle: a tool for answering questions about Go source code.
+// http://golang.org/s/oracle-design
+// http://golang.org/s/oracle-user-manual
+//
+// Run with -help flag or help subcommand for usage information.
+//
+package main // import "golang.org/x/tools/cmd/oracle"
+
+import (
+	"bufio"
+	"encoding/json"
+	"encoding/xml"
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"log"
+	"os"
+	"runtime"
+	"runtime/pprof"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/go/loader"
+	"golang.org/x/tools/oracle"
+)
+
+var posFlag = flag.String("pos", "",
+	"Filename and byte offset or extent of a syntax element about which to query, "+
+		"e.g. foo.go:#123,#456, bar.go:#123.")
+
+var ptalogFlag = flag.String("ptalog", "",
+	"Location of the points-to analysis log file, or empty to disable logging.")
+
+var formatFlag = flag.String("format", "plain", "Output format.  One of {plain,json,xml}.")
+
+var reflectFlag = flag.Bool("reflect", false, "Analyze reflection soundly (slow).")
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+}
+
+const useHelp = "Run 'oracle -help' for more information.\n"
+
+const helpMessage = `Go source code oracle.
+Usage: oracle [<flag> ...] <mode> <args> ...
+
+The -format flag controls the output format:
+	plain	an editor-friendly format in which every line of output
+		is of the form "pos: text", where pos is "-" if unknown.
+	json	structured data in JSON syntax.
+	xml	structured data in XML syntax.
+
+The -pos flag is required in all modes.
+
+The mode argument determines the query to perform:
+
+	callees	  	show possible targets of selected function call
+	callers	  	show possible callers of selected function
+	callstack 	show path from callgraph root to selected function
+	definition	show declaration of selected identifier
+	describe  	describe selected syntax: definition, methods, etc
+	freevars  	show free variables of selection
+	implements	show 'implements' relation for selected type or method
+	peers     	show send/receive corresponding to selected channel op
+	referrers 	show all refs to entity denoted by selected identifier
+	what		show basic information about the selected syntax node
+
+The user manual is available here:  http://golang.org/s/oracle-user-manual
+
+Examples:
+
+Describe the syntax at offset 530 in this file (an import spec):
+% oracle -pos=src/golang.org/x/tools/cmd/oracle/main.go:#530 describe \
+   golang.org/x/tools/cmd/oracle
+
+Print the callgraph of the trivial web-server in JSON format:
+% oracle -format=json $GOROOT/src/net/http/triv.go callgraph
+` + loader.FromArgsUsage
+
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
+
+func init() {
+	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
+	// For small machines, use at least 4 threads.
+	if os.Getenv("GOMAXPROCS") == "" {
+		n := runtime.NumCPU()
+		if n < 4 {
+			n = 4
+		}
+		runtime.GOMAXPROCS(n)
+	}
+}
+
+func printHelp() {
+	fmt.Fprintln(os.Stderr, helpMessage)
+	fmt.Fprintln(os.Stderr, "Flags:")
+	flag.PrintDefaults()
+}
+
+func main() {
+	// Don't print full help unless -help was requested.
+	// Just gently remind users that it's there.
+	flag.Usage = func() { fmt.Fprint(os.Stderr, useHelp) }
+	flag.CommandLine.Init(os.Args[0], flag.ContinueOnError) // hack
+	if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
+		// (err has already been printed)
+		if err == flag.ErrHelp {
+			printHelp()
+		}
+		os.Exit(2)
+	}
+
+	args := flag.Args()
+	if len(args) == 0 || args[0] == "" {
+		fmt.Fprint(os.Stderr, "oracle: a mode argument is required.\n"+useHelp)
+		os.Exit(2)
+	}
+
+	mode := args[0]
+	args = args[1:]
+	if mode == "help" {
+		printHelp()
+		os.Exit(2)
+	}
+
+	// Set up points-to analysis log file.
+	var ptalog io.Writer
+	if *ptalogFlag != "" {
+		if f, err := os.Create(*ptalogFlag); err != nil {
+			log.Fatalf("Failed to create PTA log file: %s", err)
+		} else {
+			buf := bufio.NewWriter(f)
+			ptalog = buf
+			defer func() {
+				if err := buf.Flush(); err != nil {
+					log.Printf("flush: %s", err)
+				}
+				if err := f.Close(); err != nil {
+					log.Printf("close: %s", err)
+				}
+			}()
+		}
+	}
+
+	// Profiling support.
+	if *cpuprofile != "" {
+		f, err := os.Create(*cpuprofile)
+		if err != nil {
+			log.Fatal(err)
+		}
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+	}
+
+	// -format flag
+	switch *formatFlag {
+	case "json", "plain", "xml":
+		// ok
+	default:
+		fmt.Fprintf(os.Stderr, "oracle: illegal -format value: %q.\n"+useHelp, *formatFlag)
+		os.Exit(2)
+	}
+
+	// Ask the oracle.
+	query := oracle.Query{
+		Mode:       mode,
+		Pos:        *posFlag,
+		Build:      &build.Default,
+		Scope:      args,
+		PTALog:     ptalog,
+		Reflection: *reflectFlag,
+	}
+
+	if err := oracle.Run(&query); err != nil {
+		fmt.Fprintf(os.Stderr, "oracle: %s\n", err)
+		os.Exit(1)
+	}
+
+	// Print the result.
+	switch *formatFlag {
+	case "json":
+		b, err := json.MarshalIndent(query.Serial(), "", "\t")
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "oracle: JSON error: %s\n", err)
+			os.Exit(1)
+		}
+		os.Stdout.Write(b)
+
+	case "xml":
+		b, err := xml.MarshalIndent(query.Serial(), "", "\t")
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "oracle: XML error: %s\n", err)
+			os.Exit(1)
+		}
+		os.Stdout.Write(b)
+
+	case "plain":
+		query.WriteTo(os.Stdout)
+	}
+}
diff --git a/cmd/oracle/oracle.el b/cmd/oracle/oracle.el
new file mode 100644
index 0000000..33c7409
--- /dev/null
+++ b/cmd/oracle/oracle.el
@@ -0,0 +1,230 @@
+;;;
+;;; Integration of the Go 'oracle' analysis tool into Emacs.
+;;;
+;;; To install the Go oracle, run:
+;;; % export GOROOT=... GOPATH=...
+;;; % go get golang.org/x/tools/cmd/oracle
+;;; % mv $GOPATH/bin/oracle $GOROOT/bin/
+;;;
+;;; Load this file into Emacs and set go-oracle-scope to your
+;;; configuration. Then, find a file of Go source code, enable
+;;; go-oracle-mode, select an expression of interest, and press `C-c C-o d'
+;;; (for "describe") or run one of the other go-oracle-xxx commands.
+;;;
+;;; TODO(adonovan): simplify installation and configuration by making
+;;; oracle a subcommand of 'go tool'.
+
+(require 'compile)
+(require 'go-mode)
+(require 'cl)
+
+(defgroup go-oracle nil
+  "Options specific to the Go oracle."
+  :group 'go)
+
+(defcustom go-oracle-command "oracle"
+  "The Go oracle command."
+  :type 'string
+  :group 'go-oracle)
+
+(defcustom go-oracle-scope ""
+  "The scope of the analysis.  See `go-oracle-set-scope'."
+  :type 'string
+  :group 'go-oracle)
+
+(defvar go-oracle--scope-history
+  nil
+  "History of values supplied to `go-oracle-set-scope'.")
+
+;; Extend go-mode-map.
+(let ((m go-mode-map))
+  (define-key m (kbd "C-c C-o t") #'go-oracle-describe) ; t for type
+  (define-key m (kbd "C-c C-o f") #'go-oracle-freevars)
+  (define-key m (kbd "C-c C-o g") #'go-oracle-callgraph)
+  (define-key m (kbd "C-c C-o i") #'go-oracle-implements)
+  (define-key m (kbd "C-c C-o c") #'go-oracle-peers)  ; c for channel
+  (define-key m (kbd "C-c C-o r") #'go-oracle-referrers)
+  (define-key m (kbd "C-c C-o d") #'go-oracle-definition)
+  (define-key m (kbd "C-c C-o p") #'go-oracle-pointsto)
+  (define-key m (kbd "C-c C-o s") #'go-oracle-callstack)
+  (define-key m (kbd "C-c C-o <") #'go-oracle-callers)
+  (define-key m (kbd "C-c C-o >") #'go-oracle-callees)
+  (define-key m (kbd "<f5>") #'go-oracle-describe)
+  (define-key m (kbd "<f6>") #'go-oracle-referrers))
+
+;; TODO(dominikh): Rethink set-scope some. Setting it to a file is
+;; painful because it doesn't use find-file, and variables/~ aren't
+;; expanded. Setting it to an import path is somewhat painful because
+;; it doesn't make use of go-mode's import path completion. One option
+;; would be having two different functions, but then we can't
+;; automatically call it when no scope has been set. Also it wouldn't
+;; easily allow specifying more than one file/package.
+(defun go-oracle-set-scope ()
+  "Set the scope for the Go oracle, prompting the user to edit the
+previous scope.
+
+The scope specifies a set of arguments, separated by spaces.
+It may be:
+1) a set of packages whose main() functions will be analyzed.
+2) a list of *.go filenames; they will treated like as a single
+   package (see #3).
+3) a single package whose main() function and/or Test* functions
+   will be analyzed.
+
+In the common case, this is similar to the argument(s) you would
+specify to 'go build'."
+  (interactive)
+  (let ((scope (read-from-minibuffer "Go oracle scope: "
+                                     go-oracle-scope
+                                     nil
+                                     nil
+                                     'go-oracle--scope-history)))
+    (if (string-equal "" scope)
+        (error "You must specify a non-empty scope for the Go oracle"))
+    (setq go-oracle-scope scope)))
+
+(defun go-oracle--run (mode &optional need-scope)
+  "Run the Go oracle in the specified MODE, passing it the
+selected region of the current buffer.  If NEED-SCOPE, prompt for
+a scope if not already set.  Process the output to replace each
+file name with a small hyperlink.  Display the result."
+  (if (not buffer-file-name)
+      (error "Cannot use oracle on a buffer without a file name"))
+  ;; It's not sufficient to save a modified buffer since if
+  ;; gofmt-before-save is on the before-save-hook, saving will
+  ;; disturb the selected region.
+  (if (buffer-modified-p)
+      (error "Please save the buffer before invoking go-oracle"))
+  (and need-scope
+       (string-equal "" go-oracle-scope)
+       (go-oracle-set-scope))
+  (let* ((filename (file-truename buffer-file-name))
+         (posflag (if (use-region-p)
+                      (format "-pos=%s:#%d,#%d"
+                              filename
+                              (1- (go--position-bytes (region-beginning)))
+                              (1- (go--position-bytes (region-end))))
+                    (format "-pos=%s:#%d"
+                            filename
+                            (1- (position-bytes (point))))))
+         (env-vars (go-root-and-paths))
+         (goroot-env (concat "GOROOT=" (car env-vars)))
+         (gopath-env (concat "GOPATH=" (mapconcat #'identity (cdr env-vars) ":"))))
+    (with-current-buffer (get-buffer-create "*go-oracle*")
+      (setq buffer-read-only nil)
+      (erase-buffer)
+      (insert "Go Oracle\n")
+      (let ((args (append (list go-oracle-command nil t nil posflag mode)
+                          (split-string go-oracle-scope " " t))))
+        ;; Log the command to *Messages*, for debugging.
+        (message "Command: %s:" args)
+        (message nil) ; clears/shrinks minibuffer
+
+        (message "Running oracle...")
+        ;; Use dynamic binding to modify/restore the environment
+        (let ((process-environment (list* goroot-env gopath-env process-environment)))
+            (apply #'call-process args)))
+      (insert "\n")
+      (compilation-mode)
+      (setq compilation-error-screen-columns nil)
+
+      ;; Hide the file/line info to save space.
+      ;; Replace each with a little widget.
+      ;; compilation-mode + this loop = slooow.
+      ;; TODO(adonovan): have oracle give us JSON
+      ;; and we'll do the markup directly.
+      (let ((buffer-read-only nil)
+            (p 1))
+        (while (not (null p))
+          (let ((np (compilation-next-single-property-change p 'compilation-message)))
+            (if np
+                (when (equal (line-number-at-pos p) (line-number-at-pos np))
+                  ;; Using a fixed width greatly improves readability, so
+                  ;; if the filename is longer than 20, show ".../last/17chars.go".
+                  ;; This usually includes the last segment of the package name.
+                  ;; Don't show the line or column number.
+                  (let* ((loc (buffer-substring p np)) ; "/home/foo/go/pkg/file.go:1:2-3:4"
+                         (i (search ":" loc)))
+                    (setq loc (cond
+                               ((null i)  "...")
+                               ((>= i 17) (concat "..." (substring loc (- i 17) i)))
+                               (t         (substring loc 0 i))))
+                    ;; np is (typically) the space following ":"; consume it too.
+                    (put-text-property p np 'display (concat loc ":")))
+                  (goto-char np)
+                  (insert " ")
+                  (incf np))) ; so we don't get stuck (e.g. on a panic stack dump)
+            (setq p np)))
+        (message nil))
+
+      (let ((w (display-buffer (current-buffer))))
+        (balance-windows)
+        (shrink-window-if-larger-than-buffer w)
+        (set-window-point w (point-min))))))
+
+(defun go-oracle-callees ()
+  "Show possible callees of the function call at the current point."
+  (interactive)
+  (go-oracle--run "callees" t))
+
+(defun go-oracle-callers ()
+  "Show the set of callers of the function containing the current point."
+  (interactive)
+  (go-oracle--run "callers" t))
+
+(defun go-oracle-callgraph ()
+  "Show the callgraph of the current program."
+  (interactive)
+  (go-oracle--run "callgraph" t))
+
+(defun go-oracle-callstack ()
+  "Show an arbitrary path from a root of the call graph to the
+function containing the current point."
+  (interactive)
+  (go-oracle--run "callstack" t))
+
+(defun go-oracle-definition ()
+  "Show the definition of the selected identifier."
+  (interactive)
+  (go-oracle--run "definition"))
+
+(defun go-oracle-describe ()
+  "Describe the selected syntax, its kind, type and methods."
+  (interactive)
+  (go-oracle--run "describe"))
+
+(defun go-oracle-pointsto ()
+  "Show what the selected expression points to."
+  (interactive)
+  (go-oracle--run "pointsto" t))
+
+(defun go-oracle-implements ()
+  "Describe the 'implements' relation for types in the package
+containing the current point."
+  (interactive)
+  (go-oracle--run "implements"))
+
+(defun go-oracle-freevars ()
+  "Enumerate the free variables of the current selection."
+  (interactive)
+  (go-oracle--run "freevars"))
+
+(defun go-oracle-peers ()
+  "Enumerate the set of possible corresponding sends/receives for
+this channel receive/send operation."
+  (interactive)
+  (go-oracle--run "peers" t))
+
+(defun go-oracle-referrers ()
+  "Enumerate all references to the object denoted by the selected
+identifier."
+  (interactive)
+  (go-oracle--run "referrers"))
+
+(defun go-oracle-whicherrs ()
+  "Show globals, constants and types to which the selected
+expression (of type 'error') may refer."
+  (interactive)
+  (go-oracle--run "whicherrs" t))
+
+(provide 'go-oracle)
diff --git a/cmd/oracle/oracle.vim b/cmd/oracle/oracle.vim
new file mode 100644
index 0000000..cadda78
--- /dev/null
+++ b/cmd/oracle/oracle.vim
@@ -0,0 +1,107 @@
+" -*- text -*-
+"  oracle.vim -- Vim integration for the Go oracle.
+"
+"  Load with (e.g.)  :source oracle.vim
+"  Call with (e.g.)  :GoOracleDescribe
+"  while cursor or selection is over syntax of interest.
+"  Run :copen to show the quick-fix file.
+"
+" This is an absolutely rudimentary integration of the Go Oracle into
+" Vim's quickfix mechanism and it needs a number of usability
+" improvements before it can be practically useful to Vim users.
+" Voluntary contributions welcomed!
+"
+" TODO(adonovan):
+" - reject buffers with no filename.
+" - hide all filenames in quickfix buffer.
+
+" Get the path to the Go oracle executable.
+func! s:go_oracle_bin()
+  let [ext, sep] = (has('win32') || has('win64') ? ['.exe', ';'] : ['', ':'])
+  let go_oracle = globpath(join(split($GOPATH, sep), ','), '/bin/oracle' . ext)
+  if go_oracle == ''
+    let go_oracle = globpath($GOROOT, '/bin/oracle' . ext)
+  endif
+  return go_oracle
+endfunction
+
+let s:go_oracle = s:go_oracle_bin()
+
+func! s:qflist(output)
+  let qflist = []
+  " Parse GNU-style 'file:line.col-line.col: message' format.
+  let mx = '^\(\a:[\\/][^:]\+\|[^:]\+\):\(\d\+\):\(\d\+\):\(.*\)$'
+  for line in split(a:output, "\n")
+    let ml = matchlist(line, mx)
+    " Ignore non-match lines or warnings
+    if ml == [] || ml[4] =~ '^ warning:'
+      continue
+    endif
+    let item = {
+    \  'filename': ml[1],
+    \  'text': ml[4],
+    \  'lnum': ml[2],
+    \  'col': ml[3],
+    \}
+    let bnr = bufnr(fnameescape(ml[1]))
+    if bnr != -1
+      let item['bufnr'] = bnr
+    endif
+    call add(qflist, item)
+  endfor
+  call setqflist(qflist)
+  cwindow
+endfun
+
+func! s:getpos(l, c)
+  if &encoding != 'utf-8'
+    let buf = a:l == 1 ? '' : (join(getline(1, a:l-1), "\n") . "\n")
+    let buf .= a:c == 1 ? '' : getline('.')[:a:c-2]
+    return len(iconv(buf, &encoding, 'utf-8'))
+  endif
+  return line2byte(a:l) + (a:c-2)
+endfun
+
+func! s:RunOracle(mode, selected) range abort
+  let fname = expand('%:p')
+  let sname = get(g:, 'go_oracle_scope_file', fname)
+  if a:selected != -1
+    let pos1 = s:getpos(line("'<"), col("'<"))
+    let pos2 = s:getpos(line("'>"), col("'>"))
+    let cmd = printf('%s -pos=%s:#%d,#%d %s %s',
+      \  s:go_oracle,
+      \  shellescape(fname), pos1, pos2, a:mode, shellescape(sname))
+  else
+    let pos = s:getpos(line('.'), col('.'))
+    let cmd = printf('%s -pos=%s:#%d %s %s',
+      \  s:go_oracle,
+      \  shellescape(fname), pos, a:mode, shellescape(sname))
+  endif
+  call s:qflist(system(cmd))
+endfun
+
+" Describe the expression at the current point.
+command! -range=% GoOracleDescribe
+  \ call s:RunOracle('describe', <count>)
+
+" Show possible callees of the function call at the current point.
+command! -range=% GoOracleCallees
+  \ call s:RunOracle('callees', <count>)
+
+" Show the set of callers of the function containing the current point.
+command! -range=% GoOracleCallers
+  \ call s:RunOracle('callers', <count>)
+
+" Show the callgraph of the current program.
+command! -range=% GoOracleCallgraph
+  \ call s:RunOracle('callgraph', <count>)
+
+" Describe the 'implements' relation for types in the
+" package containing the current point.
+command! -range=% GoOracleImplements
+  \ call s:RunOracle('implements', <count>)
+
+" Enumerate the set of possible corresponding sends/receives for
+" this channel receive/send operation.
+command! -range=% GoOracleChannelPeers
+  \ call s:RunOracle('peers', <count>)
diff --git a/cmd/present/appengine.go b/cmd/present/appengine.go
new file mode 100644
index 0000000..7df536c
--- /dev/null
+++ b/cmd/present/appengine.go
@@ -0,0 +1,30 @@
+// Copyright 2012 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.
+
+// +build appengine
+
+package main
+
+import (
+	"mime"
+
+	"golang.org/x/tools/present"
+
+	_ "golang.org/x/tools/playground"
+)
+
+var basePath = "./present/"
+
+func init() {
+	initTemplates(basePath)
+	playScript(basePath, "HTTPTransport")
+	present.PlayEnabled = true
+
+	// App Engine has no /etc/mime.types
+	mime.AddExtensionType(".svg", "image/svg+xml")
+}
+
+func playable(c present.Code) bool {
+	return present.PlayEnabled && c.Play && c.Ext == ".go"
+}
diff --git a/cmd/present/dir.go b/cmd/present/dir.go
new file mode 100644
index 0000000..6845a21
--- /dev/null
+++ b/cmd/present/dir.go
@@ -0,0 +1,213 @@
+// Copyright 2012 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 main
+
+import (
+	"html/template"
+	"io"
+	"log"
+	"net/http"
+	"os"
+	"path/filepath"
+	"sort"
+
+	"golang.org/x/tools/present"
+)
+
+func init() {
+	http.HandleFunc("/", dirHandler)
+}
+
+// dirHandler serves a directory listing for the requested path, rooted at basePath.
+func dirHandler(w http.ResponseWriter, r *http.Request) {
+	if r.URL.Path == "/favicon.ico" {
+		http.Error(w, "not found", 404)
+		return
+	}
+	const base = "."
+	name := filepath.Join(base, r.URL.Path)
+	if isDoc(name) {
+		err := renderDoc(w, name)
+		if err != nil {
+			log.Println(err)
+			http.Error(w, err.Error(), 500)
+		}
+		return
+	}
+	if isDir, err := dirList(w, name); err != nil {
+		log.Println(err)
+		http.Error(w, err.Error(), 500)
+		return
+	} else if isDir {
+		return
+	}
+	http.FileServer(http.Dir(base)).ServeHTTP(w, r)
+}
+
+func isDoc(path string) bool {
+	_, ok := contentTemplate[filepath.Ext(path)]
+	return ok
+}
+
+var (
+	// dirListTemplate holds the front page template.
+	dirListTemplate *template.Template
+
+	// contentTemplate maps the presentable file extensions to the
+	// template to be executed.
+	contentTemplate map[string]*template.Template
+)
+
+func initTemplates(base string) error {
+	// Locate the template file.
+	actionTmpl := filepath.Join(base, "templates/action.tmpl")
+
+	contentTemplate = make(map[string]*template.Template)
+
+	for ext, contentTmpl := range map[string]string{
+		".slide":   "slides.tmpl",
+		".article": "article.tmpl",
+	} {
+		contentTmpl = filepath.Join(base, "templates", contentTmpl)
+
+		// Read and parse the input.
+		tmpl := present.Template()
+		tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
+		if _, err := tmpl.ParseFiles(actionTmpl, contentTmpl); err != nil {
+			return err
+		}
+		contentTemplate[ext] = tmpl
+	}
+
+	var err error
+	dirListTemplate, err = template.ParseFiles(filepath.Join(base, "templates/dir.tmpl"))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// renderDoc reads the present file, gets its template representation,
+// and executes the template, sending output to w.
+func renderDoc(w io.Writer, docFile string) error {
+	// Read the input and build the doc structure.
+	doc, err := parse(docFile, 0)
+	if err != nil {
+		return err
+	}
+
+	// Find which template should be executed.
+	tmpl := contentTemplate[filepath.Ext(docFile)]
+
+	// Execute the template.
+	return doc.Render(w, tmpl)
+}
+
+func parse(name string, mode present.ParseMode) (*present.Doc, error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	return present.Parse(f, name, 0)
+}
+
+// dirList scans the given path and writes a directory listing to w.
+// It parses the first part of each .slide file it encounters to display the
+// presentation title in the listing.
+// If the given path is not a directory, it returns (isDir == false, err == nil)
+// and writes nothing to w.
+func dirList(w io.Writer, name string) (isDir bool, err error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return false, err
+	}
+	defer f.Close()
+	fi, err := f.Stat()
+	if err != nil {
+		return false, err
+	}
+	if isDir = fi.IsDir(); !isDir {
+		return false, nil
+	}
+	fis, err := f.Readdir(0)
+	if err != nil {
+		return false, err
+	}
+	d := &dirListData{Path: name}
+	for _, fi := range fis {
+		// skip the golang.org directory
+		if name == "." && fi.Name() == "golang.org" {
+			continue
+		}
+		e := dirEntry{
+			Name: fi.Name(),
+			Path: filepath.ToSlash(filepath.Join(name, fi.Name())),
+		}
+		if fi.IsDir() && showDir(e.Name) {
+			d.Dirs = append(d.Dirs, e)
+			continue
+		}
+		if isDoc(e.Name) {
+			if p, err := parse(e.Path, present.TitlesOnly); err != nil {
+				log.Println(err)
+			} else {
+				e.Title = p.Title
+			}
+			switch filepath.Ext(e.Path) {
+			case ".article":
+				d.Articles = append(d.Articles, e)
+			case ".slide":
+				d.Slides = append(d.Slides, e)
+			}
+		} else if showFile(e.Name) {
+			d.Other = append(d.Other, e)
+		}
+	}
+	if d.Path == "." {
+		d.Path = ""
+	}
+	sort.Sort(d.Dirs)
+	sort.Sort(d.Slides)
+	sort.Sort(d.Articles)
+	sort.Sort(d.Other)
+	return true, dirListTemplate.Execute(w, d)
+}
+
+// showFile reports whether the given file should be displayed in the list.
+func showFile(n string) bool {
+	switch filepath.Ext(n) {
+	case ".pdf":
+	case ".html":
+	case ".go":
+	default:
+		return isDoc(n)
+	}
+	return true
+}
+
+// showDir reports whether the given directory should be displayed in the list.
+func showDir(n string) bool {
+	if len(n) > 0 && (n[0] == '.' || n[0] == '_') || n == "present" {
+		return false
+	}
+	return true
+}
+
+type dirListData struct {
+	Path                          string
+	Dirs, Slides, Articles, Other dirEntrySlice
+}
+
+type dirEntry struct {
+	Name, Path, Title string
+}
+
+type dirEntrySlice []dirEntry
+
+func (s dirEntrySlice) Len() int           { return len(s) }
+func (s dirEntrySlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+func (s dirEntrySlice) Less(i, j int) bool { return s[i].Name < s[j].Name }
diff --git a/cmd/present/doc.go b/cmd/present/doc.go
new file mode 100644
index 0000000..fafcefe
--- /dev/null
+++ b/cmd/present/doc.go
@@ -0,0 +1,31 @@
+// 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.
+
+/*
+Present displays slide presentations and articles. It runs a web server that
+presents slide and article files from the current directory.
+
+It may be run as a stand-alone command or an App Engine app.
+Instructions for deployment to App Engine are in the README of the
+golang.org/x/tools repository.
+
+Usage of present:
+  -base="": base path for slide template and static resources
+  -http="127.0.0.1:3999": HTTP service address (e.g., '127.0.0.1:3999')
+  -nacl=false: use Native Client environment playground (prevents non-Go code execution)
+  -orighost="": host component of web origin URL (e.g., 'localhost')
+  -play=true: enable playground (permit execution of arbitrary user code)
+
+The setup of the Go version of NaCl is documented at:
+https://golang.org/wiki/NativeClient
+
+Input files are named foo.extension, where "extension" defines the format of
+the generated output. The supported formats are:
+	.slide        // HTML5 slide presentation
+	.article      // article format, such as a blog post
+
+The present file format is documented by the present package:
+http://godoc.org/golang.org/x/tools/present
+*/
+package main // import "golang.org/x/tools/cmd/present"
diff --git a/cmd/present/local.go b/cmd/present/local.go
new file mode 100644
index 0000000..d91dcc2
--- /dev/null
+++ b/cmd/present/local.go
@@ -0,0 +1,145 @@
+// Copyright 2013 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.
+
+// +build !appengine
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"log"
+	"net"
+	"net/http"
+	"net/url"
+	"os"
+	"runtime"
+	"strings"
+
+	"golang.org/x/tools/playground/socket"
+	"golang.org/x/tools/present"
+)
+
+const basePkg = "golang.org/x/tools/cmd/present"
+
+var basePath string
+
+func main() {
+	httpAddr := flag.String("http", "127.0.0.1:3999", "HTTP service address (e.g., '127.0.0.1:3999')")
+	originHost := flag.String("orighost", "", "host component of web origin URL (e.g., 'localhost')")
+	flag.StringVar(&basePath, "base", "", "base path for slide template and static resources")
+	flag.BoolVar(&present.PlayEnabled, "play", true, "enable playground (permit execution of arbitrary user code)")
+	nativeClient := flag.Bool("nacl", false, "use Native Client environment playground (prevents non-Go code execution)")
+	flag.Parse()
+
+	if basePath == "" {
+		p, err := build.Default.Import(basePkg, "", build.FindOnly)
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "Couldn't find gopresent files: %v\n", err)
+			fmt.Fprintf(os.Stderr, basePathMessage, basePkg)
+			os.Exit(1)
+		}
+		basePath = p.Dir
+	}
+	err := initTemplates(basePath)
+	if err != nil {
+		log.Fatalf("Failed to parse templates: %v", err)
+	}
+
+	ln, err := net.Listen("tcp", *httpAddr)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer ln.Close()
+
+	_, port, err := net.SplitHostPort(ln.Addr().String())
+	if err != nil {
+		log.Fatal(err)
+	}
+	origin := &url.URL{Scheme: "http"}
+	if *originHost != "" {
+		origin.Host = net.JoinHostPort(*originHost, port)
+	} else if ln.Addr().(*net.TCPAddr).IP.IsUnspecified() {
+		name, _ := os.Hostname()
+		origin.Host = net.JoinHostPort(name, port)
+	} else {
+		reqHost, reqPort, err := net.SplitHostPort(*httpAddr)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if reqPort == "0" {
+			origin.Host = net.JoinHostPort(reqHost, port)
+		} else {
+			origin.Host = *httpAddr
+		}
+	}
+
+	if present.PlayEnabled {
+		if *nativeClient {
+			socket.RunScripts = false
+			socket.Environ = func() []string {
+				if runtime.GOARCH == "amd64" {
+					return environ("GOOS=nacl", "GOARCH=amd64p32")
+				}
+				return environ("GOOS=nacl")
+			}
+		}
+		playScript(basePath, "SocketTransport")
+		http.Handle("/socket", socket.NewHandler(origin))
+	}
+	http.Handle("/static/", http.FileServer(http.Dir(basePath)))
+
+	if !ln.Addr().(*net.TCPAddr).IP.IsLoopback() &&
+		present.PlayEnabled && !*nativeClient {
+		log.Print(localhostWarning)
+	}
+
+	log.Printf("Open your web browser and visit %s", origin.String())
+	log.Fatal(http.Serve(ln, nil))
+}
+
+func playable(c present.Code) bool {
+	return present.PlayEnabled && c.Play
+}
+
+func environ(vars ...string) []string {
+	env := os.Environ()
+	for _, r := range vars {
+		k := strings.SplitAfter(r, "=")[0]
+		var found bool
+		for i, v := range env {
+			if strings.HasPrefix(v, k) {
+				env[i] = r
+				found = true
+			}
+		}
+		if !found {
+			env = append(env, r)
+		}
+	}
+	return env
+}
+
+const basePathMessage = `
+By default, gopresent locates the slide template files and associated
+static content by looking for a %q package
+in your Go workspaces (GOPATH).
+
+You may use the -base flag to specify an alternate location.
+`
+
+const localhostWarning = `
+WARNING!  WARNING!  WARNING!
+
+The present server appears to be listening on an address that is not localhost.
+Anyone with access to this address and port will have access to this machine as
+the user running present.
+
+To avoid this message, listen on localhost or run with -play=false.
+
+If you don't understand this message, hit Control-C to terminate this process.
+
+WARNING!  WARNING!  WARNING!
+`
diff --git a/cmd/present/play.go b/cmd/present/play.go
new file mode 100644
index 0000000..831b99f
--- /dev/null
+++ b/cmd/present/play.go
@@ -0,0 +1,43 @@
+// Copyright 2012 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"path/filepath"
+	"time"
+
+	"golang.org/x/tools/godoc/static"
+)
+
+var scripts = []string{"jquery.js", "jquery-ui.js", "playground.js", "play.js"}
+
+// playScript registers an HTTP handler at /play.js that serves all the
+// scripts specified by the variable above, and appends a line that
+// initializes the playground with the specified transport.
+func playScript(root, transport string) {
+	modTime := time.Now()
+	var buf bytes.Buffer
+	for _, p := range scripts {
+		if s, ok := static.Files[p]; ok {
+			buf.WriteString(s)
+			continue
+		}
+		b, err := ioutil.ReadFile(filepath.Join(root, "static", p))
+		if err != nil {
+			panic(err)
+		}
+		buf.Write(b)
+	}
+	fmt.Fprintf(&buf, "\ninitPlayground(new %v());\n", transport)
+	b := buf.Bytes()
+	http.HandleFunc("/play.js", func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("Content-type", "application/javascript")
+		http.ServeContent(w, r, "", modTime, bytes.NewReader(b))
+	})
+}
diff --git a/cmd/present/static/article.css b/cmd/present/static/article.css
new file mode 100644
index 0000000..e6ab1e8
--- /dev/null
+++ b/cmd/present/static/article.css
@@ -0,0 +1,136 @@
+body {
+	margin: 0;
+	font-family: Helvetica, Arial, sans-serif;
+	font-size: 16px;
+}
+pre,
+code {
+	font-family: Menlo, monospace;
+	font-size: 14px;
+}
+pre {
+	line-height: 18px;
+	margin: 0;
+	padding: 0;
+}
+a {
+	color: #375EAB;
+	text-decoration: none;
+}
+a:hover {
+	text-decoration: underline;
+}
+p, ul, ol {
+	margin: 20px;
+}
+
+h1, h2, h3, h4 {
+	margin: 20px 0;
+	padding: 0;
+	color: #375EAB;
+	font-weight: bold;
+}
+h1 {
+	font-size: 24px;
+}
+h2 {
+	font-size: 20px;
+	background: #E0EBF5;
+	padding: 2px 5px;
+}
+h3 {
+	font-size: 20px;
+}
+h3, h4 {
+	margin: 20px 5px;
+}
+h4 {
+	font-size: 16px;
+}
+
+div#heading {
+	float: left;
+	margin: 0 0 10px 0;
+	padding: 21px 0;
+	font-size: 20px;
+	font-weight: normal;
+}
+
+div#topbar {
+	background: #E0EBF5;
+	height: 64px;
+	overflow: hidden;
+}
+
+body {
+	text-align: center;
+}
+div#page {
+	width: 100%;
+}
+div#page > .container,
+div#topbar > .container {
+	text-align: left;
+	margin-left: auto;
+	margin-right: auto;
+	padding: 0 20px;
+	width: 900px;
+}
+div#page.wide > .container,
+div#topbar.wide > .container {
+	width: auto;
+}
+
+div#footer {
+	text-align: center;
+	color: #666;
+	font-size: 14px;
+	margin: 40px 0;
+}
+
+.author p {
+	margin: 20, 0, 0, 0px;
+}
+
+div.code,
+div.output {
+	margin: 20px;
+	padding: 10px;
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
+}
+
+div.code { background: #e9e9e9; }
+div.output { background: black; }
+div.output .stdout { color: #e6e6e6; }
+div.output .stderr { color: rgb(244, 74, 63); }
+div.output .system { color: rgb(255, 209, 77) }
+
+.buttons {
+	margin-left: 20px;
+}
+div.output .buttons {
+	margin-left: 0;
+	margin-bottom: 10px;
+}
+
+#toc {
+	float: right;
+	margin: 0px 10px;
+	padding: 10px;
+	border: 1px solid #e5ecf9; 
+	background-color: white;
+	max-width: 33%;
+
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
+}
+
+#toc ul, #toc a {
+	list-style-type: none;
+	padding-left: 10px;
+	color: black;
+	margin: 0px;
+}
diff --git a/cmd/present/static/dir.css b/cmd/present/static/dir.css
new file mode 100644
index 0000000..97587e6
--- /dev/null
+++ b/cmd/present/static/dir.css
@@ -0,0 +1,186 @@
+/* copied from $GOROOT/doc/style.css */
+
+body {
+	margin: 0;
+	font-family: Helvetica, Arial, sans-serif;
+	font-size: 16px;
+}
+pre,
+code {
+	font-family: Menlo, monospace;
+	font-size: 14px;
+}
+pre {
+	line-height: 18px;
+}
+pre .comment {
+	color: #375EAB;
+}
+pre .highlight,
+pre .highlight-comment,
+pre .selection-highlight,
+pre .selection-highlight-comment {
+	background: #FFFF00;
+}
+pre .selection,
+pre .selection-comment {
+	background: #FF9632;
+}
+pre .ln {
+	color: #999;
+}
+body {
+	color: #222;
+}
+a,
+.exampleHeading .text {
+	color: #375EAB;
+	text-decoration: none;
+}
+a:hover,
+.exampleHeading .text:hover {
+	text-decoration: underline;
+}
+p,
+pre,
+ul,
+ol {
+	margin: 20px;
+}
+pre {
+	background: #e9e9e9;
+	padding: 10px;
+
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
+}
+
+h1,
+h2,
+h3,
+h4,
+.rootHeading {
+	margin: 20px 0;
+	padding: 0;
+	color: #375EAB;
+	font-weight: bold;
+}
+h1 {
+	font-size: 24px;
+}
+h2 {
+	font-size: 20px;
+	background: #E0EBF5;
+	padding: 2px 5px;
+}
+h3 {
+	font-size: 20px;
+}
+h3,
+h4 {
+	margin: 20px 5px;
+}
+h4 {
+	font-size: 16px;
+}
+
+dl {
+	margin: 20px;
+}
+dd {
+	margin: 2px 20px;
+}
+dl,
+dd {
+	font-size: 14px;
+}
+div#nav table td {
+	vertical-align: top;
+}
+
+div#heading {
+	float: left;
+	margin: 0 0 10px 0;
+	padding: 21px 0;
+	font-size: 20px;
+	font-weight: normal;
+}
+div#heading a {
+	color: #222;
+	text-decoration: none;
+}
+
+div#topbar {
+	background: #E0EBF5;
+	height: 64px;
+}
+
+body {
+	text-align: center;
+}
+div#page,
+div#topbar > .container {
+	clear: both;
+	text-align: left;
+	margin-left: auto;
+	margin-right: auto;
+	padding: 0 20px;
+	width: 900px;
+}
+div#page.wide,
+div#topbar > .wide {
+	width: auto;
+}
+div#plusone {
+	float: right;
+}
+
+div#footer {
+	color: #666;
+	font-size: 14px;
+	margin: 40px 0;
+}
+
+div#menu > a,
+div#menu > input {
+	padding: 10px;
+
+	text-decoration: none;
+	font-size: 16px;
+
+	-webkit-border-radius: 5px;
+	-moz-border-radius: 5px;
+	border-radius: 5px;
+}
+div#menu > a,
+div#menu > input {
+	border: 1px solid #375EAB;
+}
+div#menu > a {
+	color: white;
+	background: #375EAB;
+}
+
+div#menu {
+	float: right;
+	min-width: 590px;
+	padding: 10px 0;
+	text-align: right;
+}
+div#menu > a {
+	margin-right: 5px;
+	margin-bottom: 10px;
+
+	padding: 10px;
+}
+div#menu > input {
+	position: relative;
+	top: 1px;
+	width: 60px;
+	background: white;
+	color: #222;
+}
+div#menu > input.inactive {
+	color: #999;
+}
diff --git a/cmd/present/static/dir.js b/cmd/present/static/dir.js
new file mode 100644
index 0000000..5b0c37e
--- /dev/null
+++ b/cmd/present/static/dir.js
@@ -0,0 +1,41 @@
+// Copyright 2012 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.
+
+// copied from $GOROOT/doc/godocs.js
+
+function bindEvent(el, e, fn) {
+  if (el.addEventListener){
+    el.addEventListener(e, fn, false);
+  } else if (el.attachEvent){
+    el.attachEvent('on'+e, fn);
+  }
+}
+
+function godocs_bindSearchEvents() {
+  var search = document.getElementById('search');
+  if (!search) {
+    // no search box (index disabled)
+    return;
+  }
+  function clearInactive() {
+    if (search.className == "inactive") {
+      search.value = "";
+      search.className = "";
+    }
+  }
+  function restoreInactive() {
+    if (search.value !== "") {
+      return;
+    }
+    if (search.type != "search") {
+      search.value = search.getAttribute("placeholder");
+    }
+    search.className = "inactive";
+  }
+  restoreInactive();
+  bindEvent(search, 'focus', clearInactive);
+  bindEvent(search, 'blur', restoreInactive);
+}
+
+bindEvent(window, 'load', godocs_bindSearchEvents);
diff --git a/cmd/present/static/favicon.ico b/cmd/present/static/favicon.ico
new file mode 100644
index 0000000..48854ff
--- /dev/null
+++ b/cmd/present/static/favicon.ico
Binary files differ
diff --git a/cmd/present/static/jquery-ui.js b/cmd/present/static/jquery-ui.js
new file mode 100644
index 0000000..f391938
--- /dev/null
+++ b/cmd/present/static/jquery-ui.js
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.10.2 - 2013-03-20
+* http://jqueryui.com
+* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.resizable.js
+* Copyright 2013 jQuery Foundation and other contributors Licensed MIT */
+
+(function(e,t){function i(t,i){var a,n,r,o=t.nodeName.toLowerCase();return"area"===o?(a=t.parentNode,n=a.name,t.href&&n&&"map"===a.nodeName.toLowerCase()?(r=e("img[usemap=#"+n+"]")[0],!!r&&s(r)):!1):(/input|select|textarea|button|object/.test(o)?!t.disabled:"a"===o?t.href||i:i)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().addBack().filter(function(){return"hidden"===e.css(this,"visibility")}).length}var a=0,n=/^ui-id-\d+$/;e.ui=e.ui||{},e.extend(e.ui,{version:"1.10.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({focus:function(t){return function(i,s){return"number"==typeof i?this.each(function(){var t=this;setTimeout(function(){e(t).focus(),s&&s.call(t)},i)}):t.apply(this,arguments)}}(e.fn.focus),scrollParent:function(){var t;return t=e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(i){if(i!==t)return this.css("zIndex",i);if(this.length)for(var s,a,n=e(this[0]);n.length&&n[0]!==document;){if(s=n.css("position"),("absolute"===s||"relative"===s||"fixed"===s)&&(a=parseInt(n.css("zIndex"),10),!isNaN(a)&&0!==a))return a;n=n.parent()}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++a)})},removeUniqueId:function(){return this.each(function(){n.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(i){return!!e.data(i,t)}}):function(t,i,s){return!!e.data(t,s[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var s=e.attr(t,"tabindex"),a=isNaN(s);return(a||s>=0)&&i(t,!a)}}),e("<a>").outerWidth(1).jquery||e.each(["Width","Height"],function(i,s){function a(t,i,s,a){return e.each(n,function(){i-=parseFloat(e.css(t,"padding"+this))||0,s&&(i-=parseFloat(e.css(t,"border"+this+"Width"))||0),a&&(i-=parseFloat(e.css(t,"margin"+this))||0)}),i}var n="Width"===s?["Left","Right"]:["Top","Bottom"],r=s.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+s]=function(i){return i===t?o["inner"+s].call(this):this.each(function(){e(this).css(r,a(this,i)+"px")})},e.fn["outer"+s]=function(t,i){return"number"!=typeof t?o["outer"+s].call(this,t):this.each(function(){e(this).css(r,a(this,t,!0,i)+"px")})}}),e.fn.addBack||(e.fn.addBack=function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}),e("<a>").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(i){return arguments.length?t.call(this,e.camelCase(i)):t.call(this)}}(e.fn.removeData)),e.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),e.support.selectstart="onselectstart"in document.createElement("div"),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,i,s){var a,n=e.ui[t].prototype;for(a in s)n.plugins[a]=n.plugins[a]||[],n.plugins[a].push([i,s[a]])},call:function(e,t,i){var s,a=e.plugins[t];if(a&&e.element[0].parentNode&&11!==e.element[0].parentNode.nodeType)for(s=0;a.length>s;s++)e.options[a[s][0]]&&a[s][1].apply(e.element,i)}},hasScroll:function(t,i){if("hidden"===e(t).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",a=!1;return t[s]>0?!0:(t[s]=1,a=t[s]>0,t[s]=0,a)}})})(jQuery);(function(e,t){var i=0,s=Array.prototype.slice,n=e.cleanData;e.cleanData=function(t){for(var i,s=0;null!=(i=t[s]);s++)try{e(i).triggerHandler("remove")}catch(a){}n(t)},e.widget=function(i,s,n){var a,r,o,h,l={},u=i.split(".")[0];i=i.split(".")[1],a=u+"-"+i,n||(n=s,s=e.Widget),e.expr[":"][a.toLowerCase()]=function(t){return!!e.data(t,a)},e[u]=e[u]||{},r=e[u][i],o=e[u][i]=function(e,i){return this._createWidget?(arguments.length&&this._createWidget(e,i),t):new o(e,i)},e.extend(o,r,{version:n.version,_proto:e.extend({},n),_childConstructors:[]}),h=new s,h.options=e.widget.extend({},h.options),e.each(n,function(i,n){return e.isFunction(n)?(l[i]=function(){var e=function(){return s.prototype[i].apply(this,arguments)},t=function(e){return s.prototype[i].apply(this,e)};return function(){var i,s=this._super,a=this._superApply;return this._super=e,this._superApply=t,i=n.apply(this,arguments),this._super=s,this._superApply=a,i}}(),t):(l[i]=n,t)}),o.prototype=e.widget.extend(h,{widgetEventPrefix:r?h.widgetEventPrefix:i},l,{constructor:o,namespace:u,widgetName:i,widgetFullName:a}),r?(e.each(r._childConstructors,function(t,i){var s=i.prototype;e.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete r._childConstructors):s._childConstructors.push(o),e.widget.bridge(i,o)},e.widget.extend=function(i){for(var n,a,r=s.call(arguments,1),o=0,h=r.length;h>o;o++)for(n in r[o])a=r[o][n],r[o].hasOwnProperty(n)&&a!==t&&(i[n]=e.isPlainObject(a)?e.isPlainObject(i[n])?e.widget.extend({},i[n],a):e.widget.extend({},a):a);return i},e.widget.bridge=function(i,n){var a=n.prototype.widgetFullName||i;e.fn[i]=function(r){var o="string"==typeof r,h=s.call(arguments,1),l=this;return r=!o&&h.length?e.widget.extend.apply(null,[r].concat(h)):r,o?this.each(function(){var s,n=e.data(this,a);return n?e.isFunction(n[r])&&"_"!==r.charAt(0)?(s=n[r].apply(n,h),s!==n&&s!==t?(l=s&&s.jquery?l.pushStack(s.get()):s,!1):t):e.error("no such method '"+r+"' for "+i+" widget instance"):e.error("cannot call methods on "+i+" prior to initialization; "+"attempted to call method '"+r+"'")}):this.each(function(){var t=e.data(this,a);t?t.option(r||{})._init():e.data(this,a,new n(r,this))}),l}},e.Widget=function(){},e.Widget._childConstructors=[],e.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(t,s){s=e(s||this.defaultElement||this)[0],this.element=e(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),s!==this&&(e.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===s&&this.destroy()}}),this.document=e(s.style?s.ownerDocument:s.document||s),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(i,s){var n,a,r,o=i;if(0===arguments.length)return e.widget.extend({},this.options);if("string"==typeof i)if(o={},n=i.split("."),i=n.shift(),n.length){for(a=o[i]=e.widget.extend({},this.options[i]),r=0;n.length-1>r;r++)a[n[r]]=a[n[r]]||{},a=a[n[r]];if(i=n.pop(),s===t)return a[i]===t?null:a[i];a[i]=s}else{if(s===t)return this.options[i]===t?null:this.options[i];o[i]=s}return this._setOptions(o),this},_setOptions:function(e){var t;for(t in e)this._setOption(t,e[t]);return this},_setOption:function(e,t){return this.options[e]=t,"disabled"===e&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!t).attr("aria-disabled",t),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(i,s,n){var a,r=this;"boolean"!=typeof i&&(n=s,s=i,i=!1),n?(s=a=e(s),this.bindings=this.bindings.add(s)):(n=s,s=this.element,a=this.widget()),e.each(n,function(n,o){function h(){return i||r.options.disabled!==!0&&!e(this).hasClass("ui-state-disabled")?("string"==typeof o?r[o]:o).apply(r,arguments):t}"string"!=typeof o&&(h.guid=o.guid=o.guid||h.guid||e.guid++);var l=n.match(/^(\w+)\s*(.*)$/),u=l[1]+r.eventNamespace,c=l[2];c?a.delegate(c,u,h):s.bind(u,h)})},_off:function(e,t){t=(t||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(t).undelegate(t)},_delay:function(e,t){function i(){return("string"==typeof e?s[e]:e).apply(s,arguments)}var s=this;return setTimeout(i,t||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){e(t.currentTarget).addClass("ui-state-hover")},mouseleave:function(t){e(t.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){e(t.currentTarget).addClass("ui-state-focus")},focusout:function(t){e(t.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(t,i,s){var n,a,r=this.options[t];if(s=s||{},i=e.Event(i),i.type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(e.isFunction(r)&&r.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},e.each({show:"fadeIn",hide:"fadeOut"},function(t,i){e.Widget.prototype["_"+t]=function(s,n,a){"string"==typeof n&&(n={effect:n});var r,o=n?n===!0||"number"==typeof n?i:n.effect||i:t;n=n||{},"number"==typeof n&&(n={duration:n}),r=!e.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),r&&e.effects&&e.effects.effect[o]?s[t](n):o!==t&&s[o]?s[o](n.duration,n.easing,a):s.queue(function(i){e(this)[t](),a&&a.call(s[0]),i()})}})})(jQuery);(function(e){var t=!1;e(document).mouseup(function(){t=!1}),e.widget("ui.mouse",{version:"1.10.2",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var t=this;this.element.bind("mousedown."+this.widgetName,function(e){return t._mouseDown(e)}).bind("click."+this.widgetName,function(i){return!0===e.data(i.target,t.widgetName+".preventClickEvent")?(e.removeData(i.target,t.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):undefined}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(i){if(!t){this._mouseStarted&&this._mouseUp(i),this._mouseDownEvent=i;var s=this,n=1===i.which,a="string"==typeof this.options.cancel&&i.target.nodeName?e(i.target).closest(this.options.cancel).length:!1;return n&&!a&&this._mouseCapture(i)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){s.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(i)&&this._mouseDelayMet(i)&&(this._mouseStarted=this._mouseStart(i)!==!1,!this._mouseStarted)?(i.preventDefault(),!0):(!0===e.data(i.target,this.widgetName+".preventClickEvent")&&e.removeData(i.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(e){return s._mouseMove(e)},this._mouseUpDelegate=function(e){return s._mouseUp(e)},e(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),i.preventDefault(),t=!0,!0)):!0}},_mouseMove:function(t){return e.ui.ie&&(!document.documentMode||9>document.documentMode)&&!t.button?this._mouseUp(t):this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}})})(jQuery);(function(e){function t(e){return parseInt(e,10)||0}function i(e){return!isNaN(parseInt(e,10))}e.widget("ui.resizable",e.ui.mouse,{version:"1.10.2",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_create:function(){var t,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),e.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)&&(this.element.wrap(e("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.data("ui-resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),t=this.handles.split(","),this.handles={},i=0;t.length>i;i++)s=e.trim(t[i]),a="ui-resizable-"+s,n=e("<div class='ui-resizable-handle "+a+"'></div>"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(t){var i,s,n,a;t=t||this.element;for(i in this.handles)this.handles[i].constructor===String&&(this.handles[i]=e(this.handles[i],this.element).show()),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)&&(s=e(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),t.css(n,a),this._proportionallyResize()),e(this.handles[i]).length},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(e(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(e(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t,i=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),t=this.element,this.originalElement.css({position:t.css("position"),width:t.outerWidth(),height:t.outerHeight(),top:t.css("top"),left:t.css("left")}).insertAfter(t),t.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(t){var i,s,n=!1;for(i in this.handles)s=e(this.handles[i])[0],(s===t.target||e.contains(s,t.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(i){var s,n,a,o=this.options,r=this.element.position(),h=this.element;return this.resizing=!0,/absolute/.test(h.css("position"))?h.css({position:"absolute",top:h.css("top"),left:h.css("left")}):h.is(".ui-draggable")&&h.css({position:"absolute",top:r.top,left:r.left}),this._renderProxy(),s=t(this.helper.css("left")),n=t(this.helper.css("top")),o.containment&&(s+=e(o.containment).scrollLeft()||0,n+=e(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:s,top:n},this.size=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalSize=this._helper?{width:h.outerWidth(),height:h.outerHeight()}:{width:h.width(),height:h.height()},this.originalPosition={left:s,top:n},this.sizeDiff={width:h.outerWidth()-h.width(),height:h.outerHeight()-h.height()},this.originalMousePosition={left:i.pageX,top:i.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,a=e(".ui-resizable-"+this.axis).css("cursor"),e("body").css("cursor","auto"===a?this.axis+"-resize":a),h.addClass("ui-resizable-resizing"),this._propagate("start",i),!0},_mouseDrag:function(t){var i,s=this.helper,n={},a=this.originalMousePosition,o=this.axis,r=this.position.top,h=this.position.left,l=this.size.width,u=this.size.height,c=t.pageX-a.left||0,d=t.pageY-a.top||0,p=this._change[o];return p?(i=p.apply(this,[t,c,d]),this._updateVirtualBoundaries(t.shiftKey),(this._aspectRatio||t.shiftKey)&&(i=this._updateRatio(i,t)),i=this._respectSize(i,t),this._updateCache(i),this._propagate("resize",t),this.position.top!==r&&(n.top=this.position.top+"px"),this.position.left!==h&&(n.left=this.position.left+"px"),this.size.width!==l&&(n.width=this.size.width+"px"),this.size.height!==u&&(n.height=this.size.height+"px"),s.css(n),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),e.isEmptyObject(n)||this._trigger("resize",t,this.ui()),!1):!1},_mouseStop:function(t){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&e.ui.hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(e.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t,s,n,a,o,r=this.options;o={minWidth:i(r.minWidth)?r.minWidth:0,maxWidth:i(r.maxWidth)?r.maxWidth:1/0,minHeight:i(r.minHeight)?r.minHeight:0,maxHeight:i(r.maxHeight)?r.maxHeight:1/0},(this._aspectRatio||e)&&(t=o.minHeight*this.aspectRatio,n=o.minWidth/this.aspectRatio,s=o.maxHeight*this.aspectRatio,a=o.maxWidth/this.aspectRatio,t>o.minWidth&&(o.minWidth=t),n>o.minHeight&&(o.minHeight=n),o.maxWidth>s&&(o.maxWidth=s),o.maxHeight>a&&(o.maxHeight=a)),this._vBoundaries=o},_updateCache:function(e){this.offset=this.helper.offset(),i(e.left)&&(this.position.left=e.left),i(e.top)&&(this.position.top=e.top),i(e.height)&&(this.size.height=e.height),i(e.width)&&(this.size.width=e.width)},_updateRatio:function(e){var t=this.position,s=this.size,n=this.axis;return i(e.height)?e.width=e.height*this.aspectRatio:i(e.width)&&(e.height=e.width/this.aspectRatio),"sw"===n&&(e.left=t.left+(s.width-e.width),e.top=null),"nw"===n&&(e.top=t.top+(s.height-e.height),e.left=t.left+(s.width-e.width)),e},_respectSize:function(e){var t=this._vBoundaries,s=this.axis,n=i(e.width)&&t.maxWidth&&t.maxWidth<e.width,a=i(e.height)&&t.maxHeight&&t.maxHeight<e.height,o=i(e.width)&&t.minWidth&&t.minWidth>e.width,r=i(e.height)&&t.minHeight&&t.minHeight>e.height,h=this.originalPosition.left+this.originalSize.width,l=this.position.top+this.size.height,u=/sw|nw|w/.test(s),c=/nw|ne|n/.test(s);return o&&(e.width=t.minWidth),r&&(e.height=t.minHeight),n&&(e.width=t.maxWidth),a&&(e.height=t.maxHeight),o&&u&&(e.left=h-t.minWidth),n&&u&&(e.left=h-t.maxWidth),r&&c&&(e.top=l-t.minHeight),a&&c&&(e.top=l-t.maxHeight),e.width||e.height||e.left||!e.top?e.width||e.height||e.top||!e.left||(e.left=null):e.top=null,e},_proportionallyResize:function(){if(this._proportionallyResizeElements.length){var e,t,i,s,n,a=this.helper||this.element;for(e=0;this._proportionallyResizeElements.length>e;e++){if(n=this._proportionallyResizeElements[e],!this.borderDif)for(this.borderDif=[],i=[n.css("borderTopWidth"),n.css("borderRightWidth"),n.css("borderBottomWidth"),n.css("borderLeftWidth")],s=[n.css("paddingTop"),n.css("paddingRight"),n.css("paddingBottom"),n.css("paddingLeft")],t=0;i.length>t;t++)this.borderDif[t]=(parseInt(i[t],10)||0)+(parseInt(s[t],10)||0);n.css({height:a.height()-this.borderDif[0]-this.borderDif[2]||0,width:a.width()-this.borderDif[1]-this.borderDif[3]||0})}}},_renderProxy:function(){var t=this.element,i=this.options;this.elementOffset=t.offset(),this._helper?(this.helper=this.helper||e("<div style='overflow:hidden;'></div>"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(e,t){return{width:this.originalSize.width+t}},w:function(e,t){var i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(e,t,i){return{height:this.originalSize.height+i}},se:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},sw:function(t,i,s){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,i,s]))},ne:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,i,s]))},nw:function(t,i,s){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,i,s]))}},_propagate:function(t,i){e.ui.plugin.call(this,t,[i,this.ui()]),"resize"!==t&&this._trigger(t,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","animate",{stop:function(t){var i=e(this).data("ui-resizable"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&e.ui.hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(e.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&e(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(){var i,s,n,a,o,r,h,l=e(this).data("ui-resizable"),u=l.options,c=l.element,d=u.containment,p=d instanceof e?d.get(0):/parent/.test(d)?c.parent().get(0):d;p&&(l.containerElement=e(p),/document/.test(d)||d===document?(l.containerOffset={left:0,top:0},l.containerPosition={left:0,top:0},l.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}):(i=e(p),s=[],e(["Top","Right","Left","Bottom"]).each(function(e,n){s[e]=t(i.css("padding"+n))}),l.containerOffset=i.offset(),l.containerPosition=i.position(),l.containerSize={height:i.innerHeight()-s[3],width:i.innerWidth()-s[1]},n=l.containerOffset,a=l.containerSize.height,o=l.containerSize.width,r=e.ui.hasScroll(p,"left")?p.scrollWidth:o,h=e.ui.hasScroll(p)?p.scrollHeight:a,l.parentData={element:p,left:n.left,top:n.top,width:r,height:h}))},resize:function(t){var i,s,n,a,o=e(this).data("ui-resizable"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||t.shiftKey,c={top:0,left:0},d=o.containerElement;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio),o.position.top=o._helper?h.top:0),o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top,i=Math.abs((o._helper?o.offset.left-c.left:o.offset.left-c.left)+o.sizeDiff.width),s=Math.abs((o._helper?o.offset.top-c.top:o.offset.top-h.top)+o.sizeDiff.height),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a&&(i-=o.parentData.left),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio))},stop:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.containerOffset,n=t.containerPosition,a=t.containerElement,o=e(t.helper),r=o.offset(),h=o.outerWidth()-t.sizeDiff.width,l=o.outerHeight()-t.sizeDiff.height;t._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l}),t._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),e.ui.plugin.add("resizable","alsoResize",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=function(t){e(t).each(function(){var t=e(this);t.data("ui-resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};"object"!=typeof i.alsoResize||i.alsoResize.parentNode?s(i.alsoResize):i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)})},resize:function(t,i){var s=e(this).data("ui-resizable"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0},h=function(t,s){e(t).each(function(){var t=e(this),n=e(this).data("ui-resizable-alsoresize"),a={},o=s&&s.length?s:t.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var i=(n[t]||0)+(r[t]||0);i&&i>=0&&(a[t]=i||null)}),t.css(a)})};"object"!=typeof n.alsoResize||n.alsoResize.nodeType?h(n.alsoResize):e.each(n.alsoResize,function(e,t){h(e,t)})},stop:function(){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","ghost",{start:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size;t.ghost=t.originalElement.clone(),t.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),t.ghost.appendTo(t.helper)},resize:function(){var t=e(this).data("ui-resizable");t.ghost&&t.ghost.css({position:"relative",height:t.size.height,width:t.size.width})},stop:function(){var t=e(this).data("ui-resizable");t.ghost&&t.helper&&t.helper.get(0).removeChild(t.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(){var t=e(this).data("ui-resizable"),i=t.options,s=t.size,n=t.originalSize,a=t.originalPosition,o=t.axis,r="number"==typeof i.grid?[i.grid,i.grid]:i.grid,h=r[0]||1,l=r[1]||1,u=Math.round((s.width-n.width)/h)*h,c=Math.round((s.height-n.height)/l)*l,d=n.width+u,p=n.height+c,f=i.maxWidth&&d>i.maxWidth,m=i.maxHeight&&p>i.maxHeight,g=i.minWidth&&i.minWidth>d,v=i.minHeight&&i.minHeight>p;i.grid=r,g&&(d+=h),v&&(p+=l),f&&(d-=h),m&&(p-=l),/^(se|s|e)$/.test(o)?(t.size.width=d,t.size.height=p):/^(ne)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.top=a.top-c):/^(sw)$/.test(o)?(t.size.width=d,t.size.height=p,t.position.left=a.left-u):(t.size.width=d,t.size.height=p,t.position.top=a.top-c,t.position.left=a.left-u)}})})(jQuery);
\ No newline at end of file
diff --git a/cmd/present/static/slides.js b/cmd/present/static/slides.js
new file mode 100644
index 0000000..3697b4e
--- /dev/null
+++ b/cmd/present/static/slides.js
@@ -0,0 +1,526 @@
+// Copyright 2012 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.
+
+var PERMANENT_URL_PREFIX = '/static/';
+
+var SLIDE_CLASSES = ['far-past', 'past', 'current', 'next', 'far-next'];
+
+var PM_TOUCH_SENSITIVITY = 15;
+
+var curSlide;
+
+/* ---------------------------------------------------------------------- */
+/* classList polyfill by Eli Grey
+ * (http://purl.eligrey.com/github/classList.js/blob/master/classList.js) */
+
+if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
+
+(function (view) {
+
+var
+    classListProp = "classList"
+  , protoProp = "prototype"
+  , elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
+  , objCtr = Object
+    strTrim = String[protoProp].trim || function () {
+    return this.replace(/^\s+|\s+$/g, "");
+  }
+  , arrIndexOf = Array[protoProp].indexOf || function (item) {
+    for (var i = 0, len = this.length; i < len; i++) {
+      if (i in this && this[i] === item) {
+        return i;
+      }
+    }
+    return -1;
+  }
+  // Vendors: please allow content code to instantiate DOMExceptions
+  , DOMEx = function (type, message) {
+    this.name = type;
+    this.code = DOMException[type];
+    this.message = message;
+  }
+  , checkTokenAndGetIndex = function (classList, token) {
+    if (token === "") {
+      throw new DOMEx(
+          "SYNTAX_ERR"
+        , "An invalid or illegal string was specified"
+      );
+    }
+    if (/\s/.test(token)) {
+      throw new DOMEx(
+          "INVALID_CHARACTER_ERR"
+        , "String contains an invalid character"
+      );
+    }
+    return arrIndexOf.call(classList, token);
+  }
+  , ClassList = function (elem) {
+    var
+        trimmedClasses = strTrim.call(elem.className)
+      , classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
+    ;
+    for (var i = 0, len = classes.length; i < len; i++) {
+      this.push(classes[i]);
+    }
+    this._updateClassName = function () {
+      elem.className = this.toString();
+    };
+  }
+  , classListProto = ClassList[protoProp] = []
+  , classListGetter = function () {
+    return new ClassList(this);
+  }
+;
+// Most DOMException implementations don't allow calling DOMException's toString()
+// on non-DOMExceptions. Error's toString() is sufficient here.
+DOMEx[protoProp] = Error[protoProp];
+classListProto.item = function (i) {
+  return this[i] || null;
+};
+classListProto.contains = function (token) {
+  token += "";
+  return checkTokenAndGetIndex(this, token) !== -1;
+};
+classListProto.add = function (token) {
+  token += "";
+  if (checkTokenAndGetIndex(this, token) === -1) {
+    this.push(token);
+    this._updateClassName();
+  }
+};
+classListProto.remove = function (token) {
+  token += "";
+  var index = checkTokenAndGetIndex(this, token);
+  if (index !== -1) {
+    this.splice(index, 1);
+    this._updateClassName();
+  }
+};
+classListProto.toggle = function (token) {
+  token += "";
+  if (checkTokenAndGetIndex(this, token) === -1) {
+    this.add(token);
+  } else {
+    this.remove(token);
+  }
+};
+classListProto.toString = function () {
+  return this.join(" ");
+};
+
+if (objCtr.defineProperty) {
+  var classListPropDesc = {
+      get: classListGetter
+    , enumerable: true
+    , configurable: true
+  };
+  try {
+    objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+  } catch (ex) { // IE 8 doesn't support enumerable:true
+    if (ex.number === -0x7FF5EC54) {
+      classListPropDesc.enumerable = false;
+      objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+    }
+  }
+} else if (objCtr[protoProp].__defineGetter__) {
+  elemCtrProto.__defineGetter__(classListProp, classListGetter);
+}
+
+}(self));
+
+}
+/* ---------------------------------------------------------------------- */
+
+/* Slide movement */
+
+function hideHelpText() {
+  $('#help').hide();
+};
+
+function getSlideEl(no) {
+  if ((no < 0) || (no >= slideEls.length)) {
+    return null;
+  } else {
+    return slideEls[no];
+  }
+};
+
+function updateSlideClass(slideNo, className) {
+  var el = getSlideEl(slideNo);
+
+  if (!el) {
+    return;
+  }
+
+  if (className) {
+    el.classList.add(className);
+  }
+
+  for (var i in SLIDE_CLASSES) {
+    if (className != SLIDE_CLASSES[i]) {
+      el.classList.remove(SLIDE_CLASSES[i]);
+    }
+  }
+};
+
+function updateSlides() {
+  if (window.trackPageview) window.trackPageview();
+
+  for (var i = 0; i < slideEls.length; i++) {
+    switch (i) {
+      case curSlide - 2:
+        updateSlideClass(i, 'far-past');
+        break;
+      case curSlide - 1:
+        updateSlideClass(i, 'past');
+        break;
+      case curSlide:
+        updateSlideClass(i, 'current');
+        break;
+      case curSlide + 1:
+        updateSlideClass(i, 'next');
+        break;
+      case curSlide + 2:
+        updateSlideClass(i, 'far-next');
+        break;
+      default:
+        updateSlideClass(i);
+        break;
+    }
+  }
+
+  triggerLeaveEvent(curSlide - 1);
+  triggerEnterEvent(curSlide);
+
+  window.setTimeout(function() {
+    // Hide after the slide
+    disableSlideFrames(curSlide - 2);
+  }, 301);
+
+  enableSlideFrames(curSlide - 1);
+  enableSlideFrames(curSlide + 2);
+
+  updateHash();
+};
+
+function prevSlide() {
+  hideHelpText();
+  if (curSlide > 0) {
+    curSlide--;
+
+    updateSlides();
+  }
+};
+
+function nextSlide() {
+  hideHelpText();
+  if (curSlide < slideEls.length - 1) {
+    curSlide++;
+
+    updateSlides();
+  }
+};
+
+/* Slide events */
+
+function triggerEnterEvent(no) {
+  var el = getSlideEl(no);
+  if (!el) {
+    return;
+  }
+
+  var onEnter = el.getAttribute('onslideenter');
+  if (onEnter) {
+    new Function(onEnter).call(el);
+  }
+
+  var evt = document.createEvent('Event');
+  evt.initEvent('slideenter', true, true);
+  evt.slideNumber = no + 1; // Make it readable
+
+  el.dispatchEvent(evt);
+};
+
+function triggerLeaveEvent(no) {
+  var el = getSlideEl(no);
+  if (!el) {
+    return;
+  }
+
+  var onLeave = el.getAttribute('onslideleave');
+  if (onLeave) {
+    new Function(onLeave).call(el);
+  }
+
+  var evt = document.createEvent('Event');
+  evt.initEvent('slideleave', true, true);
+  evt.slideNumber = no + 1; // Make it readable
+
+  el.dispatchEvent(evt);
+};
+
+/* Touch events */
+
+function handleTouchStart(event) {
+  if (event.touches.length == 1) {
+    touchDX = 0;
+    touchDY = 0;
+
+    touchStartX = event.touches[0].pageX;
+    touchStartY = event.touches[0].pageY;
+
+    document.body.addEventListener('touchmove', handleTouchMove, true);
+    document.body.addEventListener('touchend', handleTouchEnd, true);
+  }
+};
+
+function handleTouchMove(event) {
+  if (event.touches.length > 1) {
+    cancelTouch();
+  } else {
+    touchDX = event.touches[0].pageX - touchStartX;
+    touchDY = event.touches[0].pageY - touchStartY;
+    event.preventDefault();
+  }
+};
+
+function handleTouchEnd(event) {
+  var dx = Math.abs(touchDX);
+  var dy = Math.abs(touchDY);
+
+  if ((dx > PM_TOUCH_SENSITIVITY) && (dy < (dx * 2 / 3))) {
+    if (touchDX > 0) {
+      prevSlide();
+    } else {
+      nextSlide();
+    }
+  }
+
+  cancelTouch();
+};
+
+function cancelTouch() {
+  document.body.removeEventListener('touchmove', handleTouchMove, true);
+  document.body.removeEventListener('touchend', handleTouchEnd, true);
+};
+
+/* Preloading frames */
+
+function disableSlideFrames(no) {
+  var el = getSlideEl(no);
+  if (!el) {
+    return;
+  }
+
+  var frames = el.getElementsByTagName('iframe');
+  for (var i = 0, frame; frame = frames[i]; i++) {
+    disableFrame(frame);
+  }
+};
+
+function enableSlideFrames(no) {
+  var el = getSlideEl(no);
+  if (!el) {
+    return;
+  }
+
+  var frames = el.getElementsByTagName('iframe');
+  for (var i = 0, frame; frame = frames[i]; i++) {
+    enableFrame(frame);
+  }
+};
+
+function disableFrame(frame) {
+  frame.src = 'about:blank';
+};
+
+function enableFrame(frame) {
+  var src = frame._src;
+
+  if (frame.src != src && src != 'about:blank') {
+    frame.src = src;
+  }
+};
+
+function setupFrames() {
+  var frames = document.querySelectorAll('iframe');
+  for (var i = 0, frame; frame = frames[i]; i++) {
+    frame._src = frame.src;
+    disableFrame(frame);
+  }
+
+  enableSlideFrames(curSlide);
+  enableSlideFrames(curSlide + 1);
+  enableSlideFrames(curSlide + 2);
+};
+
+function setupInteraction() {
+  /* Clicking and tapping */
+
+  var el = document.createElement('div');
+  el.className = 'slide-area';
+  el.id = 'prev-slide-area';
+  el.addEventListener('click', prevSlide, false);
+  document.querySelector('section.slides').appendChild(el);
+
+  var el = document.createElement('div');
+  el.className = 'slide-area';
+  el.id = 'next-slide-area';
+  el.addEventListener('click', nextSlide, false);
+  document.querySelector('section.slides').appendChild(el);
+
+  /* Swiping */
+
+  document.body.addEventListener('touchstart', handleTouchStart, false);
+}
+
+/* Hash functions */
+
+function getCurSlideFromHash() {
+  var slideNo = parseInt(location.hash.substr(1));
+
+  if (slideNo) {
+    curSlide = slideNo - 1;
+  } else {
+    curSlide = 0;
+  }
+};
+
+function updateHash() {
+  location.replace('#' + (curSlide + 1));
+};
+
+/* Event listeners */
+
+function handleBodyKeyDown(event) {
+  // If we're in a code element, only handle pgup/down.
+  var inCode = event.target.classList.contains("code");
+
+  switch (event.keyCode) {
+    case 72: // 'H' hides the help text
+    case 27: // escape key
+      if (!inCode) hideHelpText();
+      break;
+
+    case 39: // right arrow
+    case 13: // Enter
+    case 32: // space
+      if (inCode) break;
+    case 34: // PgDn
+      nextSlide();
+      event.preventDefault();
+      break;
+
+    case 37: // left arrow
+    case 8: // Backspace
+      if (inCode) break;
+    case 33: // PgUp
+      prevSlide();
+      event.preventDefault();
+      break;
+
+    case 40: // down arrow
+      if (inCode) break;
+      nextSlide();
+      event.preventDefault();
+      break;
+
+    case 38: // up arrow
+      if (inCode) break;
+      prevSlide();
+      event.preventDefault();
+      break;
+  }
+};
+
+function addEventListeners() {
+  document.addEventListener('keydown', handleBodyKeyDown, false);
+};
+
+/* Initialization */
+
+function addFontStyle() {
+  var el = document.createElement('link');
+  el.rel = 'stylesheet';
+  el.type = 'text/css';
+  el.href = '//fonts.googleapis.com/css?family=' +
+            'Open+Sans:regular,semibold,italic,italicsemibold|Droid+Sans+Mono';
+
+  document.body.appendChild(el);
+};
+
+function addGeneralStyle() {
+  var el = document.createElement('link');
+  el.rel = 'stylesheet';
+  el.type = 'text/css';
+  el.href = PERMANENT_URL_PREFIX + 'styles.css';
+  document.body.appendChild(el);
+
+  var el = document.createElement('meta');
+  el.name = 'viewport';
+  el.content = 'width=1100,height=750';
+  document.querySelector('head').appendChild(el);
+
+  var el = document.createElement('meta');
+  el.name = 'apple-mobile-web-app-capable';
+  el.content = 'yes';
+  document.querySelector('head').appendChild(el);
+};
+
+function showHelpText() {
+};
+
+function handleDomLoaded() {
+  slideEls = document.querySelectorAll('section.slides > article');
+
+  setupFrames();
+
+  addFontStyle();
+  addGeneralStyle();
+  addEventListeners();
+
+  updateSlides();
+
+  setupInteraction();
+
+  if (window.location.hostname == "localhost" || window.location.hostname == "127.0.0.1" || window.location.hostname == "::1") {
+    hideHelpText();
+  }
+
+  document.body.classList.add('loaded');
+};
+
+function initialize() {
+  getCurSlideFromHash();
+
+  if (window['_DEBUG']) {
+    PERMANENT_URL_PREFIX = '../';
+  }
+
+  if (window['_DCL']) {
+    handleDomLoaded();
+  } else {
+    document.addEventListener('DOMContentLoaded', handleDomLoaded, false);
+  }
+}
+
+// If ?debug exists then load the script relative instead of absolute
+if (!window['_DEBUG'] && document.location.href.indexOf('?debug') !== -1) {
+  document.addEventListener('DOMContentLoaded', function() {
+    // Avoid missing the DomContentLoaded event
+    window['_DCL'] = true
+  }, false);
+
+  window['_DEBUG'] = true;
+  var script = document.createElement('script');
+  script.type = 'text/javascript';
+  script.src = '../slides.js';
+  var s = document.getElementsByTagName('script')[0];
+  s.parentNode.insertBefore(script, s);
+
+  // Remove this script
+  s.parentNode.removeChild(s);
+} else {
+  initialize();
+}
diff --git a/cmd/present/static/styles.css b/cmd/present/static/styles.css
new file mode 100644
index 0000000..5cb2953
--- /dev/null
+++ b/cmd/present/static/styles.css
@@ -0,0 +1,523 @@
+@media screen {
+  /* Framework */
+  html {
+    height: 100%;
+  }
+
+  body {
+    margin: 0;
+    padding: 0;
+
+    display: block !important;
+
+    height: 100%;
+    min-height: 740px;
+
+    overflow-x: hidden;
+    overflow-y: auto;
+
+    background: rgb(215, 215, 215);
+    background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+    background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+    background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+    background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190)));
+
+    -webkit-font-smoothing: antialiased;
+  }
+
+  .slides {
+    width: 100%;
+    height: 100%;
+    left: 0;
+    top: 0;
+
+    position: absolute;
+
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+
+  .slides > article {
+    display: block;
+
+    position: absolute;
+    overflow: hidden;
+
+    width: 900px;
+    height: 700px;
+
+    left: 50%;
+    top: 50%;
+
+    margin-left: -450px;
+    margin-top: -350px;
+
+    padding: 40px 60px;
+
+    box-sizing: border-box;
+    -o-box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+
+    background-color: white;
+
+    border: 1px solid rgba(0, 0, 0, .3);
+
+    transition: transform .3s ease-out;
+    -o-transition: -o-transform .3s ease-out;
+    -moz-transition: -moz-transform .3s ease-out;
+    -webkit-transition: -webkit-transform .3s ease-out;
+  }
+  .slides.layout-widescreen > article {
+    margin-left: -550px;
+    width: 1100px;
+  }
+  .slides.layout-faux-widescreen > article {
+    margin-left: -550px;
+    width: 1100px;
+
+    padding: 40px 160px;
+  }
+
+  .slides.layout-widescreen > article:not(.nobackground):not(.biglogo),
+  .slides.layout-faux-widescreen > article:not(.nobackground):not(.biglogo) {
+    background-position-x: 0, 840px;
+  }
+
+  /* Clickable/tappable areas */
+
+  .slide-area {
+    z-index: 1000;
+
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 150px;
+    height: 700px;
+
+    left: 50%;
+    top: 50%;
+
+    cursor: pointer;
+    margin-top: -350px;
+
+    tap-highlight-color: transparent;
+    -o-tap-highlight-color: transparent;
+    -moz-tap-highlight-color: transparent;
+    -webkit-tap-highlight-color: transparent;
+  }
+  #prev-slide-area {
+    margin-left: -550px;
+  }
+  #next-slide-area {
+    margin-left: 400px;
+  }
+  .slides.layout-widescreen #prev-slide-area,
+  .slides.layout-faux-widescreen #prev-slide-area {
+    margin-left: -650px;
+  }
+  .slides.layout-widescreen #next-slide-area,
+  .slides.layout-faux-widescreen #next-slide-area {
+    margin-left: 500px;
+  }
+
+  /* Slides */
+
+  .slides > article {
+    display: none;
+  }
+  .slides > article.far-past {
+    display: block;
+    transform: translate(-2040px);
+    -o-transform: translate(-2040px);
+    -moz-transform: translate(-2040px);
+    -webkit-transform: translate3d(-2040px, 0, 0);
+  }
+  .slides > article.past {
+    display: block;
+    transform: translate(-1020px);
+    -o-transform: translate(-1020px);
+    -moz-transform: translate(-1020px);
+    -webkit-transform: translate3d(-1020px, 0, 0);
+  }
+  .slides > article.current {
+    display: block;
+    transform: translate(0);
+    -o-transform: translate(0);
+    -moz-transform: translate(0);
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+  .slides > article.next {
+    display: block;
+    transform: translate(1020px);
+    -o-transform: translate(1020px);
+    -moz-transform: translate(1020px);
+    -webkit-transform: translate3d(1020px, 0, 0);
+  }
+  .slides > article.far-next {
+    display: block;
+    transform: translate(2040px);
+    -o-transform: translate(2040px);
+    -moz-transform: translate(2040px);
+    -webkit-transform: translate3d(2040px, 0, 0);
+  }
+
+  .slides.layout-widescreen > article.far-past,
+  .slides.layout-faux-widescreen > article.far-past {
+    display: block;
+    transform: translate(-2260px);
+    -o-transform: translate(-2260px);
+    -moz-transform: translate(-2260px);
+    -webkit-transform: translate3d(-2260px, 0, 0);
+  }
+  .slides.layout-widescreen > article.past,
+  .slides.layout-faux-widescreen > article.past {
+    display: block;
+    transform: translate(-1130px);
+    -o-transform: translate(-1130px);
+    -moz-transform: translate(-1130px);
+    -webkit-transform: translate3d(-1130px, 0, 0);
+  }
+  .slides.layout-widescreen > article.current,
+  .slides.layout-faux-widescreen > article.current {
+    display: block;
+    transform: translate(0);
+    -o-transform: translate(0);
+    -moz-transform: translate(0);
+    -webkit-transform: translate3d(0, 0, 0);
+  }
+  .slides.layout-widescreen > article.next,
+  .slides.layout-faux-widescreen > article.next {
+    display: block;
+    transform: translate(1130px);
+    -o-transform: translate(1130px);
+    -moz-transform: translate(1130px);
+    -webkit-transform: translate3d(1130px, 0, 0);
+  }
+  .slides.layout-widescreen > article.far-next,
+  .slides.layout-faux-widescreen > article.far-next {
+    display: block;
+    transform: translate(2260px);
+    -o-transform: translate(2260px);
+    -moz-transform: translate(2260px);
+    -webkit-transform: translate3d(2260px, 0, 0);
+  }
+}
+
+@media print {
+  /* Set page layout */
+  @page {
+    size: A4 landscape;
+  }
+
+  body {
+    display: block !important;
+  }
+
+  .slides > article {
+    display: block;
+
+    position: relative;
+
+    page-break-inside: never;
+    page-break-after: always;
+
+    overflow: hidden;
+  }
+
+  h2 {
+    position: static !important;
+    margin-top: 400px !important;
+    margin-bottom: 100px !important;
+  }
+
+  div.code {
+    background: rgb(240, 240, 240);
+  }
+
+  /* Add explicit links */
+  a:link:after, a:visited:after {
+   content: " (" attr(href) ") ";
+   font-size: 50%;
+  }
+
+  #help {
+    display: none;
+    visibility: hidden;
+  }
+}
+
+/* Styles for slides */
+
+.slides > article {
+  font-family: 'Open Sans', Arial, sans-serif;
+
+  color: black;
+  text-shadow: 0 1px 1px rgba(0, 0, 0, .1);
+
+  font-size: 26px;
+  line-height: 36px;
+
+  letter-spacing: -1px;
+}
+
+b {
+  font-weight: 600;
+}
+
+a {
+  color: rgb(0, 102, 204);
+  text-decoration: none;
+}
+a:visited {
+  color: rgba(0, 102, 204, .75);
+}
+a:hover {
+  color: black;
+}
+
+p {
+  margin: 0;
+  padding: 0;
+
+  margin-top: 20px;
+}
+p:first-child {
+  margin-top: 0;
+}
+
+h1 {
+  font-size: 60px;
+  line-height: 60px;
+
+  padding: 0;
+  margin: 0;
+  margin-top: 200px;
+  margin-bottom: 5px;
+  padding-right: 40px;
+
+  font-weight: 600;
+
+  letter-spacing: -3px;
+
+  color: rgb(51, 51, 51);
+}
+
+h2 {
+  font-size: 45px;
+  line-height: 45px;
+
+  position: absolute;
+  bottom: 150px;
+
+  padding: 0;
+  margin: 0;
+  padding-right: 40px;
+
+  font-weight: 600;
+
+  letter-spacing: -2px;
+
+  color: rgb(51, 51, 51);
+}
+
+h3 {
+  font-size: 30px;
+  line-height: 36px;
+
+  padding: 0;
+  margin: 0;
+  padding-right: 40px;
+
+  font-weight: 600;
+
+  letter-spacing: -1px;
+
+  color: rgb(51, 51, 51);
+}
+
+ul {
+  margin: 0;
+  padding: 0;
+  margin-top: 20px;
+  margin-left: 1.5em;
+}
+li {
+  padding: 0;
+  margin: 0 0 .5em 0;
+}
+
+div.code {
+  padding: 5px 10px;
+  margin-top: 20px;
+  margin-bottom: 20px;
+  overflow: hidden;
+
+  background: rgb(240, 240, 240);
+  border: 1px solid rgb(224, 224, 224);
+}
+pre {
+  margin: 0;
+  padding: 0;
+
+  font-family: 'Droid Sans Mono', 'Courier New', monospace;
+  font-size: 18px;
+  line-height: 24px;
+  letter-spacing: -1px;
+
+  color: black;
+}
+
+code {
+  font-size: 95%;
+  font-family: 'Droid Sans Mono', 'Courier New', monospace;
+
+  color: black;
+}
+
+article > .image {
+  text-align: center;
+  margin-top: 40px;
+}
+
+table {
+  width: 100%;
+  border-collapse: collapse;
+  margin-top: 40px;
+}
+th {
+  font-weight: 600;
+  text-align: left;
+}
+td,
+th {
+  border: 1px solid rgb(224, 224, 224);
+  padding: 5px 10px;
+  vertical-align: top;
+}
+
+p.link {
+  margin-left: 20px;
+}
+
+/* Code */
+div.code {
+  outline: 0px solid transparent;
+}
+div.playground {
+  position: relative;
+}
+div.output {
+  position: absolute;
+  left: 50%;
+  top: 50%;
+  right: 40px;
+  bottom: 40px;
+  background: #202020;
+  padding: 5px 10px;
+  z-index: 2;
+
+  border-radius: 10px;
+  -o-border-radius: 10px;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+
+}
+div.output pre {
+  margin: 0;
+  padding: 0;
+  background: none;
+  border: none;
+  width: 100%;
+  height: 100%;
+  overflow: auto;
+}
+div.output .stdout, div.output pre {
+  color: #e6e6e6;
+}
+div.output .stderr, div.output .error {
+  color: rgb(255, 200, 200);
+}
+div.output .system, div.output .exit {
+  color: rgb(255, 230, 120)
+}
+.buttons {
+  position: relative;
+  float: right;
+  top: -60px;
+  right: 10px;
+}
+div.output .buttons {
+  position: absolute;
+  float: none;
+  top: auto;
+  right: 5px;
+  bottom: 5px;
+}
+
+/* Presenter details */
+.presenter {
+  margin-top: 20px;
+}
+.presenter p,
+.presenter .link {
+  margin: 0;
+  font-size: 28px;
+  line-height: 1.2em;
+}
+
+/* Output resize details */
+.ui-resizable-handle {
+  position: absolute;
+}
+.ui-resizable-n {
+  cursor: n-resize;
+  height: 7px;
+  width: 100%;
+  top: -5px;
+  left: 0;
+}
+.ui-resizable-w {
+  cursor: w-resize;
+  width: 7px;
+  left: -5px;
+  top: 0;
+  height: 100%;
+}
+.ui-resizable-nw {
+  cursor: nw-resize;
+  width: 9px;
+  height: 9px;
+  left: -5px;
+  top: -5px;
+}
+iframe {
+  border: none;
+}
+figcaption {
+  color: #666;
+  text-align: center;
+  font-size: 0.75em;
+}
+
+#help {
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-align: center;
+  color: white;
+  background: #000;
+  opacity: 0.5;
+  position: fixed;
+  bottom: 25px;
+  left: 50px;
+  right: 50px;
+  padding: 20px;
+
+  border-radius: 10px;
+  -o-border-radius: 10px;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+}
diff --git a/cmd/present/templates/action.tmpl b/cmd/present/templates/action.tmpl
new file mode 100644
index 0000000..2893058
--- /dev/null
+++ b/cmd/present/templates/action.tmpl
@@ -0,0 +1,48 @@
+{/*
+This is the action template.
+It determines how the formatting actions are rendered.
+*/}
+
+{{define "section"}}
+  <h{{len .Number}} id="TOC_{{.FormattedNumber}}">{{.FormattedNumber}} {{.Title}}</h{{len .Number}}>
+  {{range .Elem}}{{elem $.Template .}}{{end}}
+{{end}}
+
+{{define "list"}}
+  <ul>
+  {{range .Bullet}}
+    <li>{{style .}}</li>
+  {{end}}
+  </ul>
+{{end}}
+
+{{define "text"}}
+  {{if .Pre}}
+  <div class="code"><pre>{{range .Lines}}{{.}}{{end}}</pre></div>
+  {{else}}
+  <p>
+    {{range $i, $l := .Lines}}{{if $i}}{{template "newline"}}
+    {{end}}{{style $l}}{{end}}
+  </p>
+  {{end}}
+{{end}}
+
+{{define "code"}}
+  <div class="code{{if playable .}} playground{{end}}" contenteditable="true" spellcheck="false">{{.Text}}</div>
+{{end}}
+
+{{define "image"}}
+<div class="image">
+  <img src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}>
+</div>
+{{end}}
+
+{{define "iframe"}}
+<iframe src="{{.URL}}"{{with .Height}} height="{{.}}"{{end}}{{with .Width}} width="{{.}}"{{end}}></iframe>
+{{end}}
+
+{{define "link"}}<p class="link"><a href="{{.URL}}" target="_blank">{{style .Label}}</a></p>{{end}}
+
+{{define "html"}}{{.HTML}}{{end}}
+
+{{define "caption"}}<figcaption>{{style .Text}}</figcaption>{{end}}
\ No newline at end of file
diff --git a/cmd/present/templates/article.tmpl b/cmd/present/templates/article.tmpl
new file mode 100644
index 0000000..40d1c93
--- /dev/null
+++ b/cmd/present/templates/article.tmpl
@@ -0,0 +1,58 @@
+{/* This is the article template. It defines how articles are formatted. */}
+
+{{define "root"}}
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>{{.Title}}</title>
+    <link type="text/css" rel="stylesheet" href="/static/article.css">
+    <meta charset='utf-8'>
+  </head>
+
+  <body>
+    <div id="topbar" class="wide">
+      <div class="container">
+        <div id="heading">{{.Title}}
+          {{with .Subtitle}}{{.}}{{end}}
+        </div>
+      </div>
+    </div>
+    <div id="page" class="wide">
+      <div class="container">
+        {{with .Sections}}
+          <div id="toc">
+            {{template "TOC" .}}
+          </div>
+        {{end}}
+
+        {{range .Sections}}
+          {{elem $.Template .}}
+        {{end}}{{/* of Section block */}}
+
+        {{if .Authors}}
+          <h2>Authors</h2>
+          {{range .Authors}}
+            <div class="author">
+              {{range .Elem}}{{elem $.Template .}}{{end}}
+            </div>
+          {{end}}
+        {{end}}
+      </div>
+    </div>
+    <script src='/play.js'></script>
+  </body>
+</html>
+{{end}}
+
+{{define "TOC"}}
+  <ul>
+  {{range .}}
+    <li><a href="#TOC_{{.FormattedNumber}}">{{.Title}}</a></li>
+    {{with .Sections}}{{template "TOC" .}}{{end}}
+  {{end}}
+  </ul>
+{{end}}
+
+{{define "newline"}}
+{{/* No automatic line break. Paragraphs are free-form. */}}
+{{end}}
diff --git a/cmd/present/templates/dir.tmpl b/cmd/present/templates/dir.tmpl
new file mode 100644
index 0000000..15cf97f
--- /dev/null
+++ b/cmd/present/templates/dir.tmpl
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+  <title>Talks - The Go Programming Language</title>
+  <link type="text/css" rel="stylesheet" href="/static/dir.css">
+  <script src="/static/dir.js"></script>
+</head>
+<body>
+
+<div id="topbar"><div class="container">
+
+<form method="GET" action="//golang.org/search">
+<div id="menu">
+<a href="http://golang.org/doc/">Documents</a>
+<a href="http://golang.org/ref">References</a>
+<a href="http://golang.org/pkg/">Packages</a>
+<a href="http://golang.org/project/">The Project</a>
+<a href="http://golang.org/help/">Help</a>
+<input type="text" id="search" name="q" class="inactive" value="Search">
+</div>
+<div id="heading"><a href="/">The Go Programming Language</a></div>
+</form>
+
+</div></div>
+
+<div id="page">
+
+  <h1>Go talks</h1>
+
+  {{with .Path}}<h2>{{.}}</h2>{{end}}
+
+  {{with .Articles}}
+  <h4>Articles:</h4>
+  <dl>
+  {{range .}}
+  <dd><a href="/{{.Path}}">{{.Name}}</a>: {{.Title}}</dd>
+  {{end}}
+  </dl>
+  {{end}}
+
+  {{with .Slides}}
+  <h4>Slide decks:</h4>
+  <dl>
+  {{range .}}
+  <dd><a href="/{{.Path}}">{{.Name}}</a>: {{.Title}}</dd>
+  {{end}}
+  </dl>
+  {{end}}
+
+  {{with .Other}}
+  <h4>Files:</h4>
+  <dl>
+  {{range .}}
+  <dd><a href="/{{.Path}}">{{.Name}}</a></dd>
+  {{end}}
+  </dl>
+  {{end}}
+
+  {{with .Dirs}}
+  <h4>Sub-directories:</h4>
+  <dl>
+  {{range .}}
+  <dd><a href="/{{.Path}}">{{.Name}}</a></dd>
+  {{end}}
+  </dl>
+  {{end}}
+
+</div>
+
+<div id="footer">
+Except as <a href="https://developers.google.com/site-policies#restrictions">noted</a>,
+the content of this page is licensed under the
+Creative Commons Attribution 3.0 License,
+and code is licensed under a <a href="http://golang.org/LICENSE">BSD license</a>.<br>
+<a href="http://golang.org/doc/tos.html">Terms of Service</a> |
+<a href="http://www.google.com/intl/en/policies/privacy/">Privacy Policy</a>
+</div>
+
+</body>
+</html>
diff --git a/cmd/present/templates/slides.tmpl b/cmd/present/templates/slides.tmpl
new file mode 100644
index 0000000..11070d2
--- /dev/null
+++ b/cmd/present/templates/slides.tmpl
@@ -0,0 +1,66 @@
+{/* This is the slide template. It defines how presentations are formatted. */}
+
+{{define "root"}}
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>{{.Title}}</title>
+    <meta charset='utf-8'>
+    <script src='/static/slides.js'></script>
+  </head>
+
+  <body style='display: none'>
+
+    <section class='slides layout-widescreen'>
+      
+      <article>
+        <h1>{{.Title}}</h1>
+        {{with .Subtitle}}<h3>{{.}}</h3>{{end}}
+        {{if not .Time.IsZero}}<h3>{{.Time.Format "2 January 2006"}}</h3>{{end}}
+        {{range .Authors}}
+          <div class="presenter">
+            {{range .TextElem}}{{elem $.Template .}}{{end}}
+          </div>
+        {{end}}
+      </article>
+      
+  {{range $i, $s := .Sections}}
+  <!-- start of slide {{$s.Number}} -->
+      <article>
+      {{if $s.Elem}}
+        <h3>{{$s.Title}}</h3>
+        {{range $s.Elem}}{{elem $.Template .}}{{end}}
+      {{else}}
+        <h2>{{$s.Title}}</h2>
+      {{end}}
+      </article>
+  <!-- end of slide {{$i}} -->
+  {{end}}{{/* of Slide block */}}
+
+      <article>
+        <h3>Thank you</h3>
+        {{range .Authors}}
+          <div class="presenter">
+            {{range .Elem}}{{elem $.Template .}}{{end}}
+          </div>
+        {{end}}
+      </article>
+
+    </section>
+
+    <div id="help">
+      Use the left and right arrow keys or click the left and right
+      edges of the page to navigate between slides.<br>
+      (Press 'H' or navigate to hide this message.)
+    </div>
+
+  </body>
+  {{if .PlayEnabled}}
+  <script src='/play.js'></script>
+  {{end}}
+</html>
+{{end}}
+
+{{define "newline"}}
+<br>
+{{end}}
diff --git a/cmd/ssadump/main.go b/cmd/ssadump/main.go
new file mode 100644
index 0000000..75f1601
--- /dev/null
+++ b/cmd/ssadump/main.go
@@ -0,0 +1,186 @@
+// Copyright 2013 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.
+
+// ssadump: a tool for displaying and interpreting the SSA form of Go programs.
+package main // import "golang.org/x/tools/cmd/ssadump"
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"os"
+	"runtime"
+	"runtime/pprof"
+
+	"golang.org/x/tools/go/buildutil"
+	"golang.org/x/tools/go/loader"
+	"golang.org/x/tools/go/ssa"
+	"golang.org/x/tools/go/ssa/interp"
+	"golang.org/x/tools/go/ssa/ssautil"
+	"golang.org/x/tools/go/types"
+)
+
+var (
+	modeFlag = ssa.BuilderModeFlag(flag.CommandLine, "build", 0)
+
+	testFlag = flag.Bool("test", false, "Loads test code (*_test.go) for imported packages.")
+
+	runFlag = flag.Bool("run", false, "Invokes the SSA interpreter on the program.")
+
+	interpFlag = flag.String("interp", "", `Options controlling the SSA test interpreter.
+The value is a sequence of zero or more more of these letters:
+R	disable [R]ecover() from panic; show interpreter crash instead.
+T	[T]race execution of the program.  Best for single-threaded programs!
+`)
+)
+
+const usage = `SSA builder and interpreter.
+Usage: ssadump [<flag> ...] <args> ...
+Use -help flag to display options.
+
+Examples:
+% ssadump -build=F hello.go              # dump SSA form of a single package
+% ssadump -run -interp=T hello.go        # interpret a program, with tracing
+% ssadump -run -test unicode -- -test.v  # interpret the unicode package's tests, verbosely
+` + loader.FromArgsUsage +
+	`
+When -run is specified, ssadump will run the program.
+The entry point depends on the -test flag:
+if clear, it runs the first package named main.
+if set, it runs the tests of each package.
+`
+
+var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
+
+func init() {
+	flag.Var((*buildutil.TagsFlag)(&build.Default.BuildTags), "tags", buildutil.TagsFlagDoc)
+
+	// If $GOMAXPROCS isn't set, use the full capacity of the machine.
+	// For small machines, use at least 4 threads.
+	if os.Getenv("GOMAXPROCS") == "" {
+		n := runtime.NumCPU()
+		if n < 4 {
+			n = 4
+		}
+		runtime.GOMAXPROCS(n)
+	}
+}
+
+func main() {
+	if err := doMain(); err != nil {
+		fmt.Fprintf(os.Stderr, "ssadump: %s\n", err)
+		os.Exit(1)
+	}
+}
+
+func doMain() error {
+	flag.Parse()
+	args := flag.Args()
+
+	conf := loader.Config{Build: &build.Default}
+
+	// Choose types.Sizes from conf.Build.
+	var wordSize int64 = 8
+	switch conf.Build.GOARCH {
+	case "386", "arm":
+		wordSize = 4
+	}
+	conf.TypeChecker.Sizes = &types.StdSizes{
+		MaxAlign: 8,
+		WordSize: wordSize,
+	}
+
+	var interpMode interp.Mode
+	for _, c := range *interpFlag {
+		switch c {
+		case 'T':
+			interpMode |= interp.EnableTracing
+		case 'R':
+			interpMode |= interp.DisableRecover
+		default:
+			return fmt.Errorf("unknown -interp option: '%c'", c)
+		}
+	}
+
+	if len(args) == 0 {
+		fmt.Fprint(os.Stderr, usage)
+		os.Exit(1)
+	}
+
+	// Profiling support.
+	if *cpuprofile != "" {
+		f, err := os.Create(*cpuprofile)
+		if err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			os.Exit(1)
+		}
+		pprof.StartCPUProfile(f)
+		defer pprof.StopCPUProfile()
+	}
+
+	// Use the initial packages from the command line.
+	args, err := conf.FromArgs(args, *testFlag)
+	if err != nil {
+		return err
+	}
+
+	// The interpreter needs the runtime package.
+	if *runFlag {
+		conf.Import("runtime")
+	}
+
+	// Load, parse and type-check the whole program.
+	iprog, err := conf.Load()
+	if err != nil {
+		return err
+	}
+
+	// Create and build SSA-form program representation.
+	prog := ssautil.CreateProgram(iprog, *modeFlag)
+
+	// Build and display only the initial packages
+	// (and synthetic wrappers), unless -run is specified.
+	for _, info := range iprog.InitialPackages() {
+		prog.Package(info.Pkg).Build()
+	}
+
+	// Run the interpreter.
+	if *runFlag {
+		prog.BuildAll()
+
+		var main *ssa.Package
+		pkgs := prog.AllPackages()
+		if *testFlag {
+			// If -test, run all packages' tests.
+			if len(pkgs) > 0 {
+				main = prog.CreateTestMainPackage(pkgs...)
+			}
+			if main == nil {
+				return fmt.Errorf("no tests")
+			}
+		} else {
+			// Otherwise, run main.main.
+			for _, pkg := range pkgs {
+				if pkg.Object.Name() == "main" {
+					main = pkg
+					if main.Func("main") == nil {
+						return fmt.Errorf("no func main() in main package")
+					}
+					break
+				}
+			}
+			if main == nil {
+				return fmt.Errorf("no main package")
+			}
+		}
+
+		if runtime.GOARCH != build.Default.GOARCH {
+			return fmt.Errorf("cross-interpretation is not supported (target has GOARCH %s, interpreter has %s)",
+				build.Default.GOARCH, runtime.GOARCH)
+		}
+
+		interp.Interpret(main, interpMode, conf.TypeChecker.Sizes, main.Object.Path(), args)
+	}
+	return nil
+}
diff --git a/cmd/stress/stress.go b/cmd/stress/stress.go
new file mode 100644
index 0000000..e0ff6b4
--- /dev/null
+++ b/cmd/stress/stress.go
@@ -0,0 +1,122 @@
+// Copyright 2015 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.
+
+// TODO: syscall.SIGABRT is not defined for Plan 9 (issue #11975)
+
+// +build !plan9
+
+// The stress utility is intended for catching of episodic failures.
+// It runs a given process in parallel in a loop and collects any failures.
+// Usage:
+// 	$ stress ./fmt.test -test.run=TestSometing -test.cpu=10
+// You can also specify a number of parallel processes with -p flag;
+// instruct the utility to not kill hanged processes for gdb attach;
+// or specify the failure output you are looking for (if you want to
+// ignore some other episodic failures).
+package main
+
+import (
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"regexp"
+	"runtime"
+	"syscall"
+	"time"
+)
+
+var (
+	flagP       = flag.Int("p", runtime.NumCPU(), "run `N` processes in parallel")
+	flagTimeout = flag.Duration("timeout", 10*time.Minute, "timeout each process after `duration`")
+	flagKill    = flag.Bool("kill", true, "kill timed out processes if true, otherwise just print pid (to attach with gdb)")
+	flagFailure = flag.String("failure", "", "fail only if output matches `regexp`")
+	flagIgnore  = flag.String("ignore", "", "ignore failure if output matches `regexp`")
+)
+
+func main() {
+	flag.Parse()
+	if *flagP <= 0 || *flagTimeout <= 0 || len(flag.Args()) == 0 {
+		flag.Usage()
+		os.Exit(1)
+	}
+	var failureRe, ignoreRe *regexp.Regexp
+	if *flagFailure != "" {
+		var err error
+		if failureRe, err = regexp.Compile(*flagFailure); err != nil {
+			fmt.Println("bad failure regexp:", err)
+			os.Exit(1)
+		}
+	}
+	if *flagIgnore != "" {
+		var err error
+		if ignoreRe, err = regexp.Compile(*flagIgnore); err != nil {
+			fmt.Println("bad ignore regexp:", err)
+			os.Exit(1)
+		}
+	}
+	res := make(chan []byte)
+	for i := 0; i < *flagP; i++ {
+		go func() {
+			for {
+				cmd := exec.Command(flag.Args()[0], flag.Args()[1:]...)
+				done := make(chan bool)
+				if *flagTimeout > 0 {
+					go func() {
+						select {
+						case <-done:
+							return
+						case <-time.After(*flagTimeout):
+						}
+						if !*flagKill {
+							fmt.Printf("process %v timed out\n", cmd.Process.Pid)
+							return
+						}
+						cmd.Process.Signal(syscall.SIGABRT)
+						select {
+						case <-done:
+							return
+						case <-time.After(10 * time.Second):
+						}
+						cmd.Process.Kill()
+					}()
+				}
+				out, err := cmd.CombinedOutput()
+				close(done)
+				if err != nil && (failureRe == nil || failureRe.Match(out)) && (ignoreRe == nil || !ignoreRe.Match(out)) {
+					out = append(out, fmt.Sprintf("\n\nERROR: %v\n", err)...)
+				} else {
+					out = []byte{}
+				}
+				res <- out
+			}
+		}()
+	}
+	runs, fails := 0, 0
+	ticker := time.NewTicker(5 * time.Second).C
+	for {
+		select {
+		case out := <-res:
+			runs++
+			if len(out) == 0 {
+				continue
+			}
+			fails++
+			f, err := ioutil.TempFile("", "go-stress")
+			if err != nil {
+				fmt.Printf("failed to create temp file: %v\n", err)
+				os.Exit(1)
+			}
+			f.Write(out)
+			f.Close()
+			if len(out) > 2<<10 {
+				out = out[:2<<10]
+			}
+			fmt.Printf("\n%s\n%s\n", f.Name(), out)
+		case <-ticker:
+			fmt.Printf("%v runs so far, %v failures\n", runs, fails)
+		}
+	}
+}
diff --git a/cmd/stringer/endtoend_test.go b/cmd/stringer/endtoend_test.go
new file mode 100644
index 0000000..d71a6c1
--- /dev/null
+++ b/cmd/stringer/endtoend_test.go
@@ -0,0 +1,111 @@
+// Copyright 2014 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.
+
+// go command is not available on android
+
+// +build !android
+
+package main
+
+import (
+	"fmt"
+	"go/build"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+	"testing"
+)
+
+// This file contains a test that compiles and runs each program in testdata
+// after generating the string method for its type. The rule is that for testdata/x.go
+// we run stringer -type X and then compile and run the program. The resulting
+// binary panics if the String method for X is not correct, including for error cases.
+
+func TestEndToEnd(t *testing.T) {
+	dir, err := ioutil.TempDir("", "stringer")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(dir)
+	// Create stringer in temporary directory.
+	stringer := filepath.Join(dir, "stringer.exe")
+	err = run("go", "build", "-o", stringer, "stringer.go")
+	if err != nil {
+		t.Fatalf("building stringer: %s", err)
+	}
+	// Read the testdata directory.
+	fd, err := os.Open("testdata")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer fd.Close()
+	names, err := fd.Readdirnames(-1)
+	if err != nil {
+		t.Fatalf("Readdirnames: %s", err)
+	}
+	// Generate, compile, and run the test programs.
+	for _, name := range names {
+		if !strings.HasSuffix(name, ".go") {
+			t.Errorf("%s is not a Go file", name)
+			continue
+		}
+		if name == "cgo.go" && !build.Default.CgoEnabled {
+			t.Logf("cgo is no enabled for %s", name)
+			continue
+		}
+		// Names are known to be ASCII and long enough.
+		typeName := fmt.Sprintf("%c%s", name[0]+'A'-'a', name[1:len(name)-len(".go")])
+		stringerCompileAndRun(t, dir, stringer, typeName, name)
+	}
+}
+
+// stringerCompileAndRun runs stringer for the named file and compiles and
+// runs the target binary in directory dir. That binary will panic if the String method is incorrect.
+func stringerCompileAndRun(t *testing.T, dir, stringer, typeName, fileName string) {
+	t.Logf("run: %s %s\n", fileName, typeName)
+	source := filepath.Join(dir, fileName)
+	err := copy(source, filepath.Join("testdata", fileName))
+	if err != nil {
+		t.Fatalf("copying file to temporary directory: %s", err)
+	}
+	stringSource := filepath.Join(dir, typeName+"_string.go")
+	// Run stringer in temporary directory.
+	err = run(stringer, "-type", typeName, "-output", stringSource, source)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Run the binary in the temporary directory.
+	err = run("go", "run", stringSource, source)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+// copy copies the from file to the to file.
+func copy(to, from string) error {
+	toFd, err := os.Create(to)
+	if err != nil {
+		return err
+	}
+	defer toFd.Close()
+	fromFd, err := os.Open(from)
+	if err != nil {
+		return err
+	}
+	defer fromFd.Close()
+	_, err = io.Copy(toFd, fromFd)
+	return err
+}
+
+// run runs a single command and returns an error if it does not succeed.
+// os/exec should have this function, to be honest.
+func run(name string, arg ...string) error {
+	cmd := exec.Command(name, arg...)
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	return cmd.Run()
+}
diff --git a/cmd/stringer/golden_test.go b/cmd/stringer/golden_test.go
new file mode 100644
index 0000000..12df238
--- /dev/null
+++ b/cmd/stringer/golden_test.go
@@ -0,0 +1,258 @@
+// Copyright 2014 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.
+
+// This file contains simple golden tests for various examples.
+// Besides validating the results when the implementation changes,
+// it provides a way to look at the generated code without having
+// to execute the print statements in one's head.
+
+package main
+
+import (
+	"strings"
+	"testing"
+)
+
+// Golden represents a test case.
+type Golden struct {
+	name   string
+	input  string // input; the package clause is provided when running the test.
+	output string // exected output.
+}
+
+var golden = []Golden{
+	{"day", day_in, day_out},
+	{"offset", offset_in, offset_out},
+	{"gap", gap_in, gap_out},
+	{"num", num_in, num_out},
+	{"unum", unum_in, unum_out},
+	{"prime", prime_in, prime_out},
+}
+
+// Each example starts with "type XXX [u]int", with a single space separating them.
+
+// Simple test: enumeration of type int starting at 0.
+const day_in = `type Day int
+const (
+	Monday Day = iota
+	Tuesday
+	Wednesday
+	Thursday
+	Friday
+	Saturday
+	Sunday
+)
+`
+
+const day_out = `
+const _Day_name = "MondayTuesdayWednesdayThursdayFridaySaturdaySunday"
+
+var _Day_index = [...]uint8{0, 6, 13, 22, 30, 36, 44, 50}
+
+func (i Day) String() string {
+	if i < 0 || i >= Day(len(_Day_index)-1) {
+		return fmt.Sprintf("Day(%d)", i)
+	}
+	return _Day_name[_Day_index[i]:_Day_index[i+1]]
+}
+`
+
+// Enumeration with an offset.
+// Also includes a duplicate.
+const offset_in = `type Number int
+const (
+	_ Number = iota
+	One
+	Two
+	Three
+	AnotherOne = One  // Duplicate; note that AnotherOne doesn't appear below.
+)
+`
+
+const offset_out = `
+const _Number_name = "OneTwoThree"
+
+var _Number_index = [...]uint8{0, 3, 6, 11}
+
+func (i Number) String() string {
+	i -= 1
+	if i < 0 || i >= Number(len(_Number_index)-1) {
+		return fmt.Sprintf("Number(%d)", i+1)
+	}
+	return _Number_name[_Number_index[i]:_Number_index[i+1]]
+}
+`
+
+// Gaps and an offset.
+const gap_in = `type Gap int
+const (
+	Two Gap = 2
+	Three Gap = 3
+	Five Gap = 5
+	Six Gap = 6
+	Seven Gap = 7
+	Eight Gap = 8
+	Nine Gap = 9
+	Eleven Gap = 11
+)
+`
+
+const gap_out = `
+const (
+	_Gap_name_0 = "TwoThree"
+	_Gap_name_1 = "FiveSixSevenEightNine"
+	_Gap_name_2 = "Eleven"
+)
+
+var (
+	_Gap_index_0 = [...]uint8{0, 3, 8}
+	_Gap_index_1 = [...]uint8{0, 4, 7, 12, 17, 21}
+	_Gap_index_2 = [...]uint8{0, 6}
+)
+
+func (i Gap) String() string {
+	switch {
+	case 2 <= i && i <= 3:
+		i -= 2
+		return _Gap_name_0[_Gap_index_0[i]:_Gap_index_0[i+1]]
+	case 5 <= i && i <= 9:
+		i -= 5
+		return _Gap_name_1[_Gap_index_1[i]:_Gap_index_1[i+1]]
+	case i == 11:
+		return _Gap_name_2
+	default:
+		return fmt.Sprintf("Gap(%d)", i)
+	}
+}
+`
+
+// Signed integers spanning zero.
+const num_in = `type Num int
+const (
+	m_2 Num = -2 + iota
+	m_1
+	m0
+	m1
+	m2
+)
+`
+
+const num_out = `
+const _Num_name = "m_2m_1m0m1m2"
+
+var _Num_index = [...]uint8{0, 3, 6, 8, 10, 12}
+
+func (i Num) String() string {
+	i -= -2
+	if i < 0 || i >= Num(len(_Num_index)-1) {
+		return fmt.Sprintf("Num(%d)", i+-2)
+	}
+	return _Num_name[_Num_index[i]:_Num_index[i+1]]
+}
+`
+
+// Unsigned integers spanning zero.
+const unum_in = `type Unum uint
+const (
+	m_2 Unum = iota + 253
+	m_1
+)
+
+const (
+	m0 Unum = iota
+	m1
+	m2
+)
+`
+
+const unum_out = `
+const (
+	_Unum_name_0 = "m0m1m2"
+	_Unum_name_1 = "m_2m_1"
+)
+
+var (
+	_Unum_index_0 = [...]uint8{0, 2, 4, 6}
+	_Unum_index_1 = [...]uint8{0, 3, 6}
+)
+
+func (i Unum) String() string {
+	switch {
+	case 0 <= i && i <= 2:
+		return _Unum_name_0[_Unum_index_0[i]:_Unum_index_0[i+1]]
+	case 253 <= i && i <= 254:
+		i -= 253
+		return _Unum_name_1[_Unum_index_1[i]:_Unum_index_1[i+1]]
+	default:
+		return fmt.Sprintf("Unum(%d)", i)
+	}
+}
+`
+
+// Enough gaps to trigger a map implementation of the method.
+// Also includes a duplicate to test that it doesn't cause problems
+const prime_in = `type Prime int
+const (
+	p2 Prime = 2
+	p3 Prime = 3
+	p5 Prime = 5
+	p7 Prime = 7
+	p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
+	p11 Prime = 11
+	p13 Prime = 13
+	p17 Prime = 17
+	p19 Prime = 19
+	p23 Prime = 23
+	p29 Prime = 29
+	p37 Prime = 31
+	p41 Prime = 41
+	p43 Prime = 43
+)
+`
+
+const prime_out = `
+const _Prime_name = "p2p3p5p7p11p13p17p19p23p29p37p41p43"
+
+var _Prime_map = map[Prime]string{
+	2:  _Prime_name[0:2],
+	3:  _Prime_name[2:4],
+	5:  _Prime_name[4:6],
+	7:  _Prime_name[6:8],
+	11: _Prime_name[8:11],
+	13: _Prime_name[11:14],
+	17: _Prime_name[14:17],
+	19: _Prime_name[17:20],
+	23: _Prime_name[20:23],
+	29: _Prime_name[23:26],
+	31: _Prime_name[26:29],
+	41: _Prime_name[29:32],
+	43: _Prime_name[32:35],
+}
+
+func (i Prime) String() string {
+	if str, ok := _Prime_map[i]; ok {
+		return str
+	}
+	return fmt.Sprintf("Prime(%d)", i)
+}
+`
+
+func TestGolden(t *testing.T) {
+	for _, test := range golden {
+		var g Generator
+		input := "package test\n" + test.input
+		file := test.name + ".go"
+		g.parsePackage(".", []string{file}, input)
+		// Extract the name and type of the constant from the first line.
+		tokens := strings.SplitN(test.input, " ", 3)
+		if len(tokens) != 3 {
+			t.Fatalf("%s: need type declaration on first line", test.name)
+		}
+		g.generate(tokens[1])
+		got := string(g.format())
+		if got != test.output {
+			t.Errorf("%s: got\n====\n%s====\nexpected\n====%s", test.name, got, test.output)
+		}
+	}
+}
diff --git a/cmd/stringer/stringer.go b/cmd/stringer/stringer.go
new file mode 100644
index 0000000..be87dec
--- /dev/null
+++ b/cmd/stringer/stringer.go
@@ -0,0 +1,638 @@
+// Copyright 2014 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.
+
+// Stringer is a tool to automate the creation of methods that satisfy the fmt.Stringer
+// interface. Given the name of a (signed or unsigned) integer type T that has constants
+// defined, stringer will create a new self-contained Go source file implementing
+//	func (t T) String() string
+// The file is created in the same package and directory as the package that defines T.
+// It has helpful defaults designed for use with go generate.
+//
+// Stringer works best with constants that are consecutive values such as created using iota,
+// but creates good code regardless. In the future it might also provide custom support for
+// constant sets that are bit patterns.
+//
+// For example, given this snippet,
+//
+//	package painkiller
+//
+//	type Pill int
+//
+//	const (
+//		Placebo Pill = iota
+//		Aspirin
+//		Ibuprofen
+//		Paracetamol
+//		Acetaminophen = Paracetamol
+//	)
+//
+// running this command
+//
+//	stringer -type=Pill
+//
+// in the same directory will create the file pill_string.go, in package painkiller,
+// containing a definition of
+//
+//	func (Pill) String() string
+//
+// That method will translate the value of a Pill constant to the string representation
+// of the respective constant name, so that the call fmt.Print(painkiller.Aspirin) will
+// print the string "Aspirin".
+//
+// Typically this process would be run using go generate, like this:
+//
+//	//go:generate stringer -type=Pill
+//
+// If multiple constants have the same value, the lexically first matching name will
+// be used (in the example, Acetaminophen will print as "Paracetamol").
+//
+// With no arguments, it processes the package in the current directory.
+// Otherwise, the arguments must name a single directory holding a Go package
+// or a set of Go source files that represent a single Go package.
+//
+// The -type flag accepts a comma-separated list of types so a single run can
+// generate methods for multiple types. The default output file is t_string.go,
+// where t is the lower-cased name of the first type listed. It can be overridden
+// with the -output flag.
+//
+package main // import "golang.org/x/tools/cmd/stringer"
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	"golang.org/x/tools/go/exact"
+	"golang.org/x/tools/go/types"
+
+	_ "golang.org/x/tools/go/gcimporter"
+)
+
+var (
+	typeNames = flag.String("type", "", "comma-separated list of type names; must be set")
+	output    = flag.String("output", "", "output file name; default srcdir/<type>_string.go")
+)
+
+// Usage is a replacement usage function for the flags package.
+func Usage() {
+	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+	fmt.Fprintf(os.Stderr, "\tstringer [flags] -type T [directory]\n")
+	fmt.Fprintf(os.Stderr, "\tstringer [flags[ -type T files... # Must be a single package\n")
+	fmt.Fprintf(os.Stderr, "For more information, see:\n")
+	fmt.Fprintf(os.Stderr, "\thttp://godoc.org/golang.org/x/tools/cmd/stringer\n")
+	fmt.Fprintf(os.Stderr, "Flags:\n")
+	flag.PrintDefaults()
+}
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("stringer: ")
+	flag.Usage = Usage
+	flag.Parse()
+	if len(*typeNames) == 0 {
+		flag.Usage()
+		os.Exit(2)
+	}
+	types := strings.Split(*typeNames, ",")
+
+	// We accept either one directory or a list of files. Which do we have?
+	args := flag.Args()
+	if len(args) == 0 {
+		// Default: process whole package in current directory.
+		args = []string{"."}
+	}
+
+	// Parse the package once.
+	var (
+		dir string
+		g   Generator
+	)
+	if len(args) == 1 && isDirectory(args[0]) {
+		dir = args[0]
+		g.parsePackageDir(args[0])
+	} else {
+		dir = filepath.Dir(args[0])
+		g.parsePackageFiles(args)
+	}
+
+	// Print the header and package clause.
+	g.Printf("// generated by stringer %s; DO NOT EDIT\n", strings.Join(os.Args[1:], " "))
+	g.Printf("\n")
+	g.Printf("package %s", g.pkg.name)
+	g.Printf("\n")
+	g.Printf("import \"fmt\"\n") // Used by all methods.
+
+	// Run generate for each type.
+	for _, typeName := range types {
+		g.generate(typeName)
+	}
+
+	// Format the output.
+	src := g.format()
+
+	// Write to file.
+	outputName := *output
+	if outputName == "" {
+		baseName := fmt.Sprintf("%s_string.go", types[0])
+		outputName = filepath.Join(dir, strings.ToLower(baseName))
+	}
+	err := ioutil.WriteFile(outputName, src, 0644)
+	if err != nil {
+		log.Fatalf("writing output: %s", err)
+	}
+}
+
+// isDirectory reports whether the named file is a directory.
+func isDirectory(name string) bool {
+	info, err := os.Stat(name)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return info.IsDir()
+}
+
+// Generator holds the state of the analysis. Primarily used to buffer
+// the output for format.Source.
+type Generator struct {
+	buf bytes.Buffer // Accumulated output.
+	pkg *Package     // Package we are scanning.
+}
+
+func (g *Generator) Printf(format string, args ...interface{}) {
+	fmt.Fprintf(&g.buf, format, args...)
+}
+
+// File holds a single parsed file and associated data.
+type File struct {
+	pkg  *Package  // Package to which this file belongs.
+	file *ast.File // Parsed AST.
+	// These fields are reset for each type being generated.
+	typeName string  // Name of the constant type.
+	values   []Value // Accumulator for constant values of that type.
+}
+
+type Package struct {
+	dir      string
+	name     string
+	defs     map[*ast.Ident]types.Object
+	files    []*File
+	typesPkg *types.Package
+}
+
+// parsePackageDir parses the package residing in the directory.
+func (g *Generator) parsePackageDir(directory string) {
+	pkg, err := build.Default.ImportDir(directory, 0)
+	if err != nil {
+		log.Fatalf("cannot process directory %s: %s", directory, err)
+	}
+	var names []string
+	names = append(names, pkg.GoFiles...)
+	names = append(names, pkg.CgoFiles...)
+	// TODO: Need to think about constants in test files. Maybe write type_string_test.go
+	// in a separate pass? For later.
+	// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
+	names = append(names, pkg.SFiles...)
+	names = prefixDirectory(directory, names)
+	g.parsePackage(directory, names, nil)
+}
+
+// parsePackageFiles parses the package occupying the named files.
+func (g *Generator) parsePackageFiles(names []string) {
+	g.parsePackage(".", names, nil)
+}
+
+// prefixDirectory places the directory name on the beginning of each name in the list.
+func prefixDirectory(directory string, names []string) []string {
+	if directory == "." {
+		return names
+	}
+	ret := make([]string, len(names))
+	for i, name := range names {
+		ret[i] = filepath.Join(directory, name)
+	}
+	return ret
+}
+
+// parsePackage analyzes the single package constructed from the named files.
+// If text is non-nil, it is a string to be used instead of the content of the file,
+// to be used for testing. parsePackage exits if there is an error.
+func (g *Generator) parsePackage(directory string, names []string, text interface{}) {
+	var files []*File
+	var astFiles []*ast.File
+	g.pkg = new(Package)
+	fs := token.NewFileSet()
+	for _, name := range names {
+		if !strings.HasSuffix(name, ".go") {
+			continue
+		}
+		parsedFile, err := parser.ParseFile(fs, name, text, 0)
+		if err != nil {
+			log.Fatalf("parsing package: %s: %s", name, err)
+		}
+		astFiles = append(astFiles, parsedFile)
+		files = append(files, &File{
+			file: parsedFile,
+			pkg:  g.pkg,
+		})
+	}
+	if len(astFiles) == 0 {
+		log.Fatalf("%s: no buildable Go files", directory)
+	}
+	g.pkg.name = astFiles[0].Name.Name
+	g.pkg.files = files
+	g.pkg.dir = directory
+	// Type check the package.
+	g.pkg.check(fs, astFiles)
+}
+
+// check type-checks the package. The package must be OK to proceed.
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {
+	pkg.defs = make(map[*ast.Ident]types.Object)
+	config := types.Config{FakeImportC: true}
+	info := &types.Info{
+		Defs: pkg.defs,
+	}
+	typesPkg, err := config.Check(pkg.dir, fs, astFiles, info)
+	if err != nil {
+		log.Fatalf("checking package: %s", err)
+	}
+	pkg.typesPkg = typesPkg
+}
+
+// generate produces the String method for the named type.
+func (g *Generator) generate(typeName string) {
+	values := make([]Value, 0, 100)
+	for _, file := range g.pkg.files {
+		// Set the state for this run of the walker.
+		file.typeName = typeName
+		file.values = nil
+		if file.file != nil {
+			ast.Inspect(file.file, file.genDecl)
+			values = append(values, file.values...)
+		}
+	}
+
+	if len(values) == 0 {
+		log.Fatalf("no values defined for type %s", typeName)
+	}
+	runs := splitIntoRuns(values)
+	// The decision of which pattern to use depends on the number of
+	// runs in the numbers. If there's only one, it's easy. For more than
+	// one, there's a tradeoff between complexity and size of the data
+	// and code vs. the simplicity of a map. A map takes more space,
+	// but so does the code. The decision here (crossover at 10) is
+	// arbitrary, but considers that for large numbers of runs the cost
+	// of the linear scan in the switch might become important, and
+	// rather than use yet another algorithm such as binary search,
+	// we punt and use a map. In any case, the likelihood of a map
+	// being necessary for any realistic example other than bitmasks
+	// is very low. And bitmasks probably deserve their own analysis,
+	// to be done some other day.
+	switch {
+	case len(runs) == 1:
+		g.buildOneRun(runs, typeName)
+	case len(runs) <= 10:
+		g.buildMultipleRuns(runs, typeName)
+	default:
+		g.buildMap(runs, typeName)
+	}
+}
+
+// splitIntoRuns breaks the values into runs of contiguous sequences.
+// For example, given 1,2,3,5,6,7 it returns {1,2,3},{5,6,7}.
+// The input slice is known to be non-empty.
+func splitIntoRuns(values []Value) [][]Value {
+	// We use stable sort so the lexically first name is chosen for equal elements.
+	sort.Stable(byValue(values))
+	// Remove duplicates. Stable sort has put the one we want to print first,
+	// so use that one. The String method won't care about which named constant
+	// was the argument, so the first name for the given value is the only one to keep.
+	// We need to do this because identical values would cause the switch or map
+	// to fail to compile.
+	j := 1
+	for i := 1; i < len(values); i++ {
+		if values[i].value != values[i-1].value {
+			values[j] = values[i]
+			j++
+		}
+	}
+	values = values[:j]
+	runs := make([][]Value, 0, 10)
+	for len(values) > 0 {
+		// One contiguous sequence per outer loop.
+		i := 1
+		for i < len(values) && values[i].value == values[i-1].value+1 {
+			i++
+		}
+		runs = append(runs, values[:i])
+		values = values[i:]
+	}
+	return runs
+}
+
+// format returns the gofmt-ed contents of the Generator's buffer.
+func (g *Generator) format() []byte {
+	src, err := format.Source(g.buf.Bytes())
+	if err != nil {
+		// Should never happen, but can arise when developing this code.
+		// The user can compile the output to see the error.
+		log.Printf("warning: internal error: invalid Go generated: %s", err)
+		log.Printf("warning: compile the package to analyze the error")
+		return g.buf.Bytes()
+	}
+	return src
+}
+
+// Value represents a declared constant.
+type Value struct {
+	name string // The name of the constant.
+	// The value is stored as a bit pattern alone. The boolean tells us
+	// whether to interpret it as an int64 or a uint64; the only place
+	// this matters is when sorting.
+	// Much of the time the str field is all we need; it is printed
+	// by Value.String.
+	value  uint64 // Will be converted to int64 when needed.
+	signed bool   // Whether the constant is a signed type.
+	str    string // The string representation given by the "go/exact" package.
+}
+
+func (v *Value) String() string {
+	return v.str
+}
+
+// byValue lets us sort the constants into increasing order.
+// We take care in the Less method to sort in signed or unsigned order,
+// as appropriate.
+type byValue []Value
+
+func (b byValue) Len() int      { return len(b) }
+func (b byValue) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b byValue) Less(i, j int) bool {
+	if b[i].signed {
+		return int64(b[i].value) < int64(b[j].value)
+	}
+	return b[i].value < b[j].value
+}
+
+// genDecl processes one declaration clause.
+func (f *File) genDecl(node ast.Node) bool {
+	decl, ok := node.(*ast.GenDecl)
+	if !ok || decl.Tok != token.CONST {
+		// We only care about const declarations.
+		return true
+	}
+	// The name of the type of the constants we are declaring.
+	// Can change if this is a multi-element declaration.
+	typ := ""
+	// Loop over the elements of the declaration. Each element is a ValueSpec:
+	// a list of names possibly followed by a type, possibly followed by values.
+	// If the type and value are both missing, we carry down the type (and value,
+	// but the "go/types" package takes care of that).
+	for _, spec := range decl.Specs {
+		vspec := spec.(*ast.ValueSpec) // Guaranteed to succeed as this is CONST.
+		if vspec.Type == nil && len(vspec.Values) > 0 {
+			// "X = 1". With no type but a value, the constant is untyped.
+			// Skip this vspec and reset the remembered type.
+			typ = ""
+			continue
+		}
+		if vspec.Type != nil {
+			// "X T". We have a type. Remember it.
+			ident, ok := vspec.Type.(*ast.Ident)
+			if !ok {
+				continue
+			}
+			typ = ident.Name
+		}
+		if typ != f.typeName {
+			// This is not the type we're looking for.
+			continue
+		}
+		// We now have a list of names (from one line of source code) all being
+		// declared with the desired type.
+		// Grab their names and actual values and store them in f.values.
+		for _, name := range vspec.Names {
+			if name.Name == "_" {
+				continue
+			}
+			// This dance lets the type checker find the values for us. It's a
+			// bit tricky: look up the object declared by the name, find its
+			// types.Const, and extract its value.
+			obj, ok := f.pkg.defs[name]
+			if !ok {
+				log.Fatalf("no value for constant %s", name)
+			}
+			info := obj.Type().Underlying().(*types.Basic).Info()
+			if info&types.IsInteger == 0 {
+				log.Fatalf("can't handle non-integer constant type %s", typ)
+			}
+			value := obj.(*types.Const).Val() // Guaranteed to succeed as this is CONST.
+			if value.Kind() != exact.Int {
+				log.Fatalf("can't happen: constant is not an integer %s", name)
+			}
+			i64, isInt := exact.Int64Val(value)
+			u64, isUint := exact.Uint64Val(value)
+			if !isInt && !isUint {
+				log.Fatalf("internal error: value of %s is not an integer: %s", name, value.String())
+			}
+			if !isInt {
+				u64 = uint64(i64)
+			}
+			v := Value{
+				name:   name.Name,
+				value:  u64,
+				signed: info&types.IsUnsigned == 0,
+				str:    value.String(),
+			}
+			f.values = append(f.values, v)
+		}
+	}
+	return false
+}
+
+// Helpers
+
+// usize returns the number of bits of the smallest unsigned integer
+// type that will hold n. Used to create the smallest possible slice of
+// integers to use as indexes into the concatenated strings.
+func usize(n int) int {
+	switch {
+	case n < 1<<8:
+		return 8
+	case n < 1<<16:
+		return 16
+	default:
+		// 2^32 is enough constants for anyone.
+		return 32
+	}
+}
+
+// declareIndexAndNameVars declares the index slices and concatenated names
+// strings representing the runs of values.
+func (g *Generator) declareIndexAndNameVars(runs [][]Value, typeName string) {
+	var indexes, names []string
+	for i, run := range runs {
+		index, name := g.createIndexAndNameDecl(run, typeName, fmt.Sprintf("_%d", i))
+		indexes = append(indexes, index)
+		names = append(names, name)
+	}
+	g.Printf("const (\n")
+	for _, name := range names {
+		g.Printf("\t%s\n", name)
+	}
+	g.Printf(")\n\n")
+	g.Printf("var (")
+	for _, index := range indexes {
+		g.Printf("\t%s\n", index)
+	}
+	g.Printf(")\n\n")
+}
+
+// declareIndexAndNameVar is the single-run version of declareIndexAndNameVars
+func (g *Generator) declareIndexAndNameVar(run []Value, typeName string) {
+	index, name := g.createIndexAndNameDecl(run, typeName, "")
+	g.Printf("const %s\n", name)
+	g.Printf("var %s\n", index)
+}
+
+// createIndexAndNameDecl returns the pair of declarations for the run. The caller will add "const" and "var".
+func (g *Generator) createIndexAndNameDecl(run []Value, typeName string, suffix string) (string, string) {
+	b := new(bytes.Buffer)
+	indexes := make([]int, len(run))
+	for i := range run {
+		b.WriteString(run[i].name)
+		indexes[i] = b.Len()
+	}
+	nameConst := fmt.Sprintf("_%s_name%s = %q", typeName, suffix, b.String())
+	nameLen := b.Len()
+	b.Reset()
+	fmt.Fprintf(b, "_%s_index%s = [...]uint%d{0, ", typeName, suffix, usize(nameLen))
+	for i, v := range indexes {
+		if i > 0 {
+			fmt.Fprintf(b, ", ")
+		}
+		fmt.Fprintf(b, "%d", v)
+	}
+	fmt.Fprintf(b, "}")
+	return b.String(), nameConst
+}
+
+// declareNameVars declares the concatenated names string representing all the values in the runs.
+func (g *Generator) declareNameVars(runs [][]Value, typeName string, suffix string) {
+	g.Printf("const _%s_name%s = \"", typeName, suffix)
+	for _, run := range runs {
+		for i := range run {
+			g.Printf("%s", run[i].name)
+		}
+	}
+	g.Printf("\"\n")
+}
+
+// buildOneRun generates the variables and String method for a single run of contiguous values.
+func (g *Generator) buildOneRun(runs [][]Value, typeName string) {
+	values := runs[0]
+	g.Printf("\n")
+	g.declareIndexAndNameVar(values, typeName)
+	// The generated code is simple enough to write as a Printf format.
+	lessThanZero := ""
+	if values[0].signed {
+		lessThanZero = "i < 0 || "
+	}
+	if values[0].value == 0 { // Signed or unsigned, 0 is still 0.
+		g.Printf(stringOneRun, typeName, usize(len(values)), lessThanZero)
+	} else {
+		g.Printf(stringOneRunWithOffset, typeName, values[0].String(), usize(len(values)), lessThanZero)
+	}
+}
+
+// Arguments to format are:
+//	[1]: type name
+//	[2]: size of index element (8 for uint8 etc.)
+//	[3]: less than zero check (for signed types)
+const stringOneRun = `func (i %[1]s) String() string {
+	if %[3]si >= %[1]s(len(_%[1]s_index)-1) {
+		return fmt.Sprintf("%[1]s(%%d)", i)
+	}
+	return _%[1]s_name[_%[1]s_index[i]:_%[1]s_index[i+1]]
+}
+`
+
+// Arguments to format are:
+//	[1]: type name
+//	[2]: lowest defined value for type, as a string
+//	[3]: size of index element (8 for uint8 etc.)
+//	[4]: less than zero check (for signed types)
+/*
+ */
+const stringOneRunWithOffset = `func (i %[1]s) String() string {
+	i -= %[2]s
+	if %[4]si >= %[1]s(len(_%[1]s_index)-1) {
+		return fmt.Sprintf("%[1]s(%%d)", i + %[2]s)
+	}
+	return _%[1]s_name[_%[1]s_index[i] : _%[1]s_index[i+1]]
+}
+`
+
+// buildMultipleRuns generates the variables and String method for multiple runs of contiguous values.
+// For this pattern, a single Printf format won't do.
+func (g *Generator) buildMultipleRuns(runs [][]Value, typeName string) {
+	g.Printf("\n")
+	g.declareIndexAndNameVars(runs, typeName)
+	g.Printf("func (i %s) String() string {\n", typeName)
+	g.Printf("\tswitch {\n")
+	for i, values := range runs {
+		if len(values) == 1 {
+			g.Printf("\tcase i == %s:\n", &values[0])
+			g.Printf("\t\treturn _%s_name_%d\n", typeName, i)
+			continue
+		}
+		g.Printf("\tcase %s <= i && i <= %s:\n", &values[0], &values[len(values)-1])
+		if values[0].value != 0 {
+			g.Printf("\t\ti -= %s\n", &values[0])
+		}
+		g.Printf("\t\treturn _%s_name_%d[_%s_index_%d[i]:_%s_index_%d[i+1]]\n",
+			typeName, i, typeName, i, typeName, i)
+	}
+	g.Printf("\tdefault:\n")
+	g.Printf("\t\treturn fmt.Sprintf(\"%s(%%d)\", i)\n", typeName)
+	g.Printf("\t}\n")
+	g.Printf("}\n")
+}
+
+// buildMap handles the case where the space is so sparse a map is a reasonable fallback.
+// It's a rare situation but has simple code.
+func (g *Generator) buildMap(runs [][]Value, typeName string) {
+	g.Printf("\n")
+	g.declareNameVars(runs, typeName, "")
+	g.Printf("\nvar _%s_map = map[%s]string{\n", typeName, typeName)
+	n := 0
+	for _, values := range runs {
+		for _, value := range values {
+			g.Printf("\t%s: _%s_name[%d:%d],\n", &value, typeName, n, n+len(value.name))
+			n += len(value.name)
+		}
+	}
+	g.Printf("}\n\n")
+	g.Printf(stringMap, typeName)
+}
+
+// Argument to format is the type name.
+const stringMap = `func (i %[1]s) String() string {
+	if str, ok := _%[1]s_map[i]; ok {
+		return str
+	}
+	return fmt.Sprintf("%[1]s(%%d)", i)
+}
+`
diff --git a/cmd/stringer/testdata/cgo.go b/cmd/stringer/testdata/cgo.go
new file mode 100644
index 0000000..ef38f95
--- /dev/null
+++ b/cmd/stringer/testdata/cgo.go
@@ -0,0 +1,32 @@
+// Copyright 2014 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.
+
+// Import "C" shouldn't be imported.
+
+package main
+
+/*
+#define HELLO 1
+*/
+import "C"
+
+import "fmt"
+
+type Cgo uint32
+
+const (
+	// MustScanSubDirs indicates that events were coalesced hierarchically.
+	MustScanSubDirs Cgo = 1 << iota
+)
+
+func main() {
+	_ = C.HELLO
+	ck(MustScanSubDirs, "MustScanSubDirs")
+}
+
+func ck(day Cgo, str string) {
+	if fmt.Sprint(day) != str {
+		panic("cgo.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/day.go b/cmd/stringer/testdata/day.go
new file mode 100644
index 0000000..35fa8dc
--- /dev/null
+++ b/cmd/stringer/testdata/day.go
@@ -0,0 +1,39 @@
+// Copyright 2014 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.
+
+// Simple test: enumeration of type int starting at 0.
+
+package main
+
+import "fmt"
+
+type Day int
+
+const (
+	Monday Day = iota
+	Tuesday
+	Wednesday
+	Thursday
+	Friday
+	Saturday
+	Sunday
+)
+
+func main() {
+	ck(Monday, "Monday")
+	ck(Tuesday, "Tuesday")
+	ck(Wednesday, "Wednesday")
+	ck(Thursday, "Thursday")
+	ck(Friday, "Friday")
+	ck(Saturday, "Saturday")
+	ck(Sunday, "Sunday")
+	ck(-127, "Day(-127)")
+	ck(127, "Day(127)")
+}
+
+func ck(day Day, str string) {
+	if fmt.Sprint(day) != str {
+		panic("day.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/gap.go b/cmd/stringer/testdata/gap.go
new file mode 100644
index 0000000..bc8a90c
--- /dev/null
+++ b/cmd/stringer/testdata/gap.go
@@ -0,0 +1,44 @@
+// Copyright 2014 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.
+
+// Gaps and an offset.
+
+package main
+
+import "fmt"
+
+type Gap int
+
+const (
+	Two    Gap = 2
+	Three  Gap = 3
+	Five   Gap = 5
+	Six    Gap = 6
+	Seven  Gap = 7
+	Eight  Gap = 8
+	Nine   Gap = 9
+	Eleven Gap = 11
+)
+
+func main() {
+	ck(0, "Gap(0)")
+	ck(1, "Gap(1)")
+	ck(Two, "Two")
+	ck(Three, "Three")
+	ck(4, "Gap(4)")
+	ck(Five, "Five")
+	ck(Six, "Six")
+	ck(Seven, "Seven")
+	ck(Eight, "Eight")
+	ck(Nine, "Nine")
+	ck(10, "Gap(10)")
+	ck(Eleven, "Eleven")
+	ck(12, "Gap(12)")
+}
+
+func ck(gap Gap, str string) {
+	if fmt.Sprint(gap) != str {
+		panic("gap.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/num.go b/cmd/stringer/testdata/num.go
new file mode 100644
index 0000000..0d5ab10
--- /dev/null
+++ b/cmd/stringer/testdata/num.go
@@ -0,0 +1,35 @@
+// Copyright 2014 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.
+
+// Signed integers spanning zero.
+
+package main
+
+import "fmt"
+
+type Num int
+
+const (
+	m_2 Num = -2 + iota
+	m_1
+	m0
+	m1
+	m2
+)
+
+func main() {
+	ck(-3, "Num(-3)")
+	ck(m_2, "m_2")
+	ck(m_1, "m_1")
+	ck(m0, "m0")
+	ck(m1, "m1")
+	ck(m2, "m2")
+	ck(3, "Num(3)")
+}
+
+func ck(num Num, str string) {
+	if fmt.Sprint(num) != str {
+		panic("num.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/number.go b/cmd/stringer/testdata/number.go
new file mode 100644
index 0000000..7f1c824
--- /dev/null
+++ b/cmd/stringer/testdata/number.go
@@ -0,0 +1,34 @@
+// Copyright 2014 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.
+
+// Enumeration with an offset.
+// Also includes a duplicate.
+
+package main
+
+import "fmt"
+
+type Number int
+
+const (
+	_ Number = iota
+	One
+	Two
+	Three
+	AnotherOne = One // Duplicate; note that AnotherOne doesn't appear below.
+)
+
+func main() {
+	ck(One, "One")
+	ck(Two, "Two")
+	ck(Three, "Three")
+	ck(AnotherOne, "One")
+	ck(127, "Number(127)")
+}
+
+func ck(num Number, str string) {
+	if fmt.Sprint(num) != str {
+		panic("number.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/prime.go b/cmd/stringer/testdata/prime.go
new file mode 100644
index 0000000..f551a1a
--- /dev/null
+++ b/cmd/stringer/testdata/prime.go
@@ -0,0 +1,56 @@
+// Copyright 2014 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.
+
+// Enough gaps to trigger a map implementation of the method.
+// Also includes a duplicate to test that it doesn't cause problems
+
+package main
+
+import "fmt"
+
+type Prime int
+
+const (
+	p2  Prime = 2
+	p3  Prime = 3
+	p5  Prime = 5
+	p7  Prime = 7
+	p77 Prime = 7 // Duplicate; note that p77 doesn't appear below.
+	p11 Prime = 11
+	p13 Prime = 13
+	p17 Prime = 17
+	p19 Prime = 19
+	p23 Prime = 23
+	p29 Prime = 29
+	p37 Prime = 31
+	p41 Prime = 41
+	p43 Prime = 43
+)
+
+func main() {
+	ck(0, "Prime(0)")
+	ck(1, "Prime(1)")
+	ck(p2, "p2")
+	ck(p3, "p3")
+	ck(4, "Prime(4)")
+	ck(p5, "p5")
+	ck(p7, "p7")
+	ck(p77, "p7")
+	ck(p11, "p11")
+	ck(p13, "p13")
+	ck(p17, "p17")
+	ck(p19, "p19")
+	ck(p23, "p23")
+	ck(p29, "p29")
+	ck(p37, "p37")
+	ck(p41, "p41")
+	ck(p43, "p43")
+	ck(44, "Prime(44)")
+}
+
+func ck(prime Prime, str string) {
+	if fmt.Sprint(prime) != str {
+		panic("prime.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/unum.go b/cmd/stringer/testdata/unum.go
new file mode 100644
index 0000000..2f8508f
--- /dev/null
+++ b/cmd/stringer/testdata/unum.go
@@ -0,0 +1,38 @@
+// Copyright 2014 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.
+
+// Unsigned integers spanning zero.
+
+package main
+
+import "fmt"
+
+type Unum uint8
+
+const (
+	m_2 Unum = iota + 253
+	m_1
+)
+
+const (
+	m0 Unum = iota
+	m1
+	m2
+)
+
+func main() {
+	ck(^Unum(0)-3, "Unum(252)")
+	ck(m_2, "m_2")
+	ck(m_1, "m_1")
+	ck(m0, "m0")
+	ck(m1, "m1")
+	ck(m2, "m2")
+	ck(3, "Unum(3)")
+}
+
+func ck(unum Unum, str string) {
+	if fmt.Sprint(unum) != str {
+		panic("unum.go: " + str)
+	}
+}
diff --git a/cmd/stringer/testdata/unum2.go b/cmd/stringer/testdata/unum2.go
new file mode 100644
index 0000000..edbbedf
--- /dev/null
+++ b/cmd/stringer/testdata/unum2.go
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+// Unsigned integers - check maximum size
+
+package main
+
+import "fmt"
+
+type Unum2 uint8
+
+const (
+	Zero Unum2 = iota
+	One
+	Two
+)
+
+func main() {
+	ck(Zero, "Zero")
+	ck(One, "One")
+	ck(Two, "Two")
+	ck(3, "Unum2(3)")
+	ck(255, "Unum2(255)")
+}
+
+func ck(unum Unum2, str string) {
+	if fmt.Sprint(unum) != str {
+		panic("unum.go: " + str)
+	}
+}
diff --git a/cmd/stringer/util_test.go b/cmd/stringer/util_test.go
new file mode 100644
index 0000000..1aeba6e
--- /dev/null
+++ b/cmd/stringer/util_test.go
@@ -0,0 +1,77 @@
+// Copyright 2014 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.
+
+// This file contains tests for some of the internal functions.
+
+package main
+
+import (
+	"fmt"
+	"testing"
+)
+
+// Helpers to save typing in the test cases.
+type u []uint64
+type uu [][]uint64
+
+type SplitTest struct {
+	input  u
+	output uu
+	signed bool
+}
+
+var (
+	m2  = uint64(2)
+	m1  = uint64(1)
+	m0  = uint64(0)
+	m_1 = ^uint64(0)     // -1 when signed.
+	m_2 = ^uint64(0) - 1 // -2 when signed.
+)
+
+var splitTests = []SplitTest{
+	// No need for a test for the empty case; that's picked off before splitIntoRuns.
+	// Single value.
+	{u{1}, uu{u{1}}, false},
+	// Out of order.
+	{u{3, 2, 1}, uu{u{1, 2, 3}}, true},
+	// Out of order.
+	{u{3, 2, 1}, uu{u{1, 2, 3}}, false},
+	// A gap at the beginning.
+	{u{1, 33, 32, 31}, uu{u{1}, u{31, 32, 33}}, true},
+	// A gap in the middle, in mixed order.
+	{u{33, 7, 32, 31, 9, 8}, uu{u{7, 8, 9}, u{31, 32, 33}}, true},
+	// Gaps throughout
+	{u{33, 44, 1, 32, 45, 31}, uu{u{1}, u{31, 32, 33}, u{44, 45}}, true},
+	// Unsigned values spanning 0.
+	{u{m1, m0, m_1, m2, m_2}, uu{u{m0, m1, m2}, u{m_2, m_1}}, false},
+	// Signed values spanning 0
+	{u{m1, m0, m_1, m2, m_2}, uu{u{m_2, m_1, m0, m1, m2}}, true},
+}
+
+func TestSplitIntoRuns(t *testing.T) {
+Outer:
+	for n, test := range splitTests {
+		values := make([]Value, len(test.input))
+		for i, v := range test.input {
+			values[i] = Value{"", v, test.signed, fmt.Sprint(v)}
+		}
+		runs := splitIntoRuns(values)
+		if len(runs) != len(test.output) {
+			t.Errorf("#%d: %v: got %d runs; expected %d", n, test.input, len(runs), len(test.output))
+			continue
+		}
+		for i, run := range runs {
+			if len(run) != len(test.output[i]) {
+				t.Errorf("#%d: got %v; expected %v", n, runs, test.output)
+				continue Outer
+			}
+			for j, v := range run {
+				if v.value != test.output[i][j] {
+					t.Errorf("#%d: got %v; expected %v", n, runs, test.output)
+					continue Outer
+				}
+			}
+		}
+	}
+}
diff --git a/cmd/tipgodoc/Dockerfile b/cmd/tipgodoc/Dockerfile
new file mode 100644
index 0000000..760ca0b
--- /dev/null
+++ b/cmd/tipgodoc/Dockerfile
@@ -0,0 +1,13 @@
+FROM golang:1.4.2
+
+RUN apt-get update && apt-get install --no-install-recommends -y -q build-essential git
+
+# golang puts its go install here (weird but true)
+ENV GOROOT_BOOTSTRAP /usr/src/go
+
+# golang sets GOPATH=/go
+ADD . /go/src/tipgodoc
+RUN go install tipgodoc
+ENTRYPOINT ["/go/bin/tipgodoc"]
+# Kubernetes expects us to listen on port 8080
+EXPOSE 8080 
diff --git a/cmd/tipgodoc/README b/cmd/tipgodoc/README
new file mode 100644
index 0000000..602e546
--- /dev/null
+++ b/cmd/tipgodoc/README
@@ -0,0 +1,3 @@
+To deploy as an App Engine Manged VM, use gcloud:
+
+	$ gcloud --project golang-org preview app deploy .
diff --git a/cmd/tipgodoc/app.yaml b/cmd/tipgodoc/app.yaml
new file mode 100644
index 0000000..59e5a06
--- /dev/null
+++ b/cmd/tipgodoc/app.yaml
@@ -0,0 +1,15 @@
+application: golang-org
+version: tip
+runtime: custom
+api_version: go1
+vm: true
+
+manual_scaling:
+  instances: 1
+
+handlers:
+- url: /.*
+  script: _go_app
+
+health_check:
+  enable_health_check: False
diff --git a/cmd/tipgodoc/tip.go b/cmd/tipgodoc/tip.go
new file mode 100644
index 0000000..ab3b8e6
--- /dev/null
+++ b/cmd/tipgodoc/tip.go
@@ -0,0 +1,298 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by the Apache 2.0
+// license that can be found in the LICENSE file.
+
+// Command tipgodoc is the beginning of the new tip.golang.org server,
+// serving the latest HEAD straight from the Git oven.
+package main
+
+import (
+	"bufio"
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/http/httputil"
+	"net/url"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"sync"
+	"time"
+)
+
+const (
+	repoURL      = "https://go.googlesource.com/"
+	metaURL      = "https://go.googlesource.com/?b=master&format=JSON"
+	startTimeout = 5 * time.Minute
+)
+
+var indexingMsg = []byte("Indexing in progress: result may be inaccurate")
+
+func main() {
+	p := new(Proxy)
+	go p.run()
+	http.Handle("/", p)
+
+	if err := http.ListenAndServe(":8080", nil); err != nil {
+		p.stop()
+		log.Fatal(err)
+	}
+}
+
+// Proxy implements the tip.golang.org server: a reverse-proxy
+// that builds and runs godoc instances showing the latest docs.
+type Proxy struct {
+	mu    sync.Mutex // protects the followin'
+	proxy http.Handler
+	cur   string    // signature of gorepo+toolsrepo
+	cmd   *exec.Cmd // live godoc instance, or nil for none
+	side  string
+	err   error
+}
+
+func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	if r.URL.Path == "/_tipstatus" {
+		p.serveStatus(w, r)
+		return
+	}
+	p.mu.Lock()
+	proxy := p.proxy
+	err := p.err
+	p.mu.Unlock()
+	if proxy == nil {
+		s := "tip.golang.org is starting up"
+		if err != nil {
+			s = err.Error()
+		}
+		http.Error(w, s, http.StatusInternalServerError)
+		return
+	}
+	proxy.ServeHTTP(w, r)
+}
+
+func (p *Proxy) serveStatus(w http.ResponseWriter, r *http.Request) {
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	fmt.Fprintf(w, "side=%v\ncurrent=%v\nerror=%v\n", p.side, p.cur, p.err)
+}
+
+// run runs in its own goroutine.
+func (p *Proxy) run() {
+	p.side = "a"
+	for {
+		p.poll()
+		time.Sleep(30 * time.Second)
+	}
+}
+
+func (p *Proxy) stop() {
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	if p.cmd != nil {
+		p.cmd.Process.Kill()
+	}
+}
+
+// poll runs from the run loop goroutine.
+func (p *Proxy) poll() {
+	heads := gerritMetaMap()
+	if heads == nil {
+		return
+	}
+
+	sig := heads["go"] + "-" + heads["tools"]
+
+	p.mu.Lock()
+	changes := sig != p.cur
+	curSide := p.side
+	p.cur = sig
+	p.mu.Unlock()
+
+	if !changes {
+		return
+	}
+
+	newSide := "b"
+	if curSide == "b" {
+		newSide = "a"
+	}
+
+	cmd, hostport, err := initSide(newSide, heads["go"], heads["tools"])
+
+	p.mu.Lock()
+	defer p.mu.Unlock()
+	if err != nil {
+		log.Println(err)
+		p.err = err
+		return
+	}
+
+	u, err := url.Parse(fmt.Sprintf("http://%v/", hostport))
+	if err != nil {
+		log.Println(err)
+		p.err = err
+		return
+	}
+	p.proxy = httputil.NewSingleHostReverseProxy(u)
+	p.side = newSide
+	if p.cmd != nil {
+		p.cmd.Process.Kill()
+	}
+	p.cmd = cmd
+}
+
+func initSide(side, goHash, toolsHash string) (godoc *exec.Cmd, hostport string, err error) {
+	dir := filepath.Join(os.TempDir(), "tipgodoc", side)
+	if err := os.MkdirAll(dir, 0755); err != nil {
+		return nil, "", err
+	}
+
+	goDir := filepath.Join(dir, "go")
+	toolsDir := filepath.Join(dir, "gopath/src/golang.org/x/tools")
+	if err := checkout(repoURL+"go", goHash, goDir); err != nil {
+		return nil, "", err
+	}
+	if err := checkout(repoURL+"tools", toolsHash, toolsDir); err != nil {
+		return nil, "", err
+	}
+
+	make := exec.Command(filepath.Join(goDir, "src/make.bash"))
+	make.Dir = filepath.Join(goDir, "src")
+	if err := runErr(make); err != nil {
+		return nil, "", err
+	}
+	goBin := filepath.Join(goDir, "bin/go")
+	install := exec.Command(goBin, "install", "golang.org/x/tools/cmd/godoc")
+	install.Env = []string{
+		"GOROOT=" + goDir,
+		"GOPATH=" + filepath.Join(dir, "gopath"),
+		"GOROOT_BOOTSTRAP=" + os.Getenv("GOROOT_BOOTSTRAP"),
+	}
+	if err := runErr(install); err != nil {
+		return nil, "", err
+	}
+
+	godocBin := filepath.Join(goDir, "bin/godoc")
+	hostport = "localhost:8081"
+	if side == "b" {
+		hostport = "localhost:8082"
+	}
+	godoc = exec.Command(godocBin, "-http="+hostport, "-index", "-index_interval=-1s")
+	godoc.Env = []string{"GOROOT=" + goDir}
+	// TODO(adg): log this somewhere useful
+	godoc.Stdout = os.Stdout
+	godoc.Stderr = os.Stderr
+	if err := godoc.Start(); err != nil {
+		return nil, "", err
+	}
+	go func() {
+		// TODO(bradfitz): tell the proxy that this side is dead
+		if err := godoc.Wait(); err != nil {
+			log.Printf("side %v exited: %v", side, err)
+		}
+	}()
+
+	deadline := time.Now().Add(startTimeout)
+	for time.Now().Before(deadline) {
+		time.Sleep(time.Second)
+		var res *http.Response
+		res, err = http.Get(fmt.Sprintf("http://%v/search?q=FALLTHROUGH", hostport))
+		if err != nil {
+			continue
+		}
+		rbody, err := ioutil.ReadAll(res.Body)
+		res.Body.Close()
+		if err == nil && res.StatusCode == http.StatusOK &&
+			!bytes.Contains(rbody, indexingMsg) {
+			return godoc, hostport, nil
+		}
+	}
+	godoc.Process.Kill()
+	return nil, "", fmt.Errorf("timed out waiting for side %v at %v (%v)", side, hostport, err)
+}
+
+func runErr(cmd *exec.Cmd) error {
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		if len(out) == 0 {
+			return err
+		}
+		return fmt.Errorf("%s\n%v", out, err)
+	}
+	return nil
+}
+
+func checkout(repo, hash, path string) error {
+	// Clone git repo if it doesn't exist.
+	if _, err := os.Stat(filepath.Join(path, ".git")); os.IsNotExist(err) {
+		if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+			return err
+		}
+		if err := runErr(exec.Command("git", "clone", repo, path)); err != nil {
+			return err
+		}
+	} else if err != nil {
+		return err
+	}
+
+	// Pull down changes and update to hash.
+	cmd := exec.Command("git", "fetch")
+	cmd.Dir = path
+	if err := runErr(cmd); err != nil {
+		return err
+	}
+	cmd = exec.Command("git", "reset", "--hard", hash)
+	cmd.Dir = path
+	if err := runErr(cmd); err != nil {
+		return err
+	}
+	cmd = exec.Command("git", "clean", "-d", "-f", "-x")
+	cmd.Dir = path
+	return runErr(cmd)
+}
+
+// gerritMetaMap returns the map from repo name (e.g. "go") to its
+// latest master hash.
+// The returned map is nil on any transient error.
+func gerritMetaMap() map[string]string {
+	res, err := http.Get(metaURL)
+	if err != nil {
+		return nil
+	}
+	defer res.Body.Close()
+	defer io.Copy(ioutil.Discard, res.Body) // ensure EOF for keep-alive
+	if res.StatusCode != 200 {
+		return nil
+	}
+	var meta map[string]struct {
+		Branches map[string]string
+	}
+	br := bufio.NewReader(res.Body)
+	// For security reasons or something, this URL starts with ")]}'\n" before
+	// the JSON object. So ignore that.
+	// Shawn Pearce says it's guaranteed to always be just one line, ending in '\n'.
+	for {
+		b, err := br.ReadByte()
+		if err != nil {
+			return nil
+		}
+		if b == '\n' {
+			break
+		}
+	}
+	if err := json.NewDecoder(br).Decode(&meta); err != nil {
+		log.Printf("JSON decoding error from %v: %s", metaURL, err)
+		return nil
+	}
+	m := map[string]string{}
+	for repo, v := range meta {
+		if master, ok := v.Branches["master"]; ok {
+			m[repo] = master
+		}
+	}
+	return m
+}
diff --git a/cmd/vet/asmdecl.go b/cmd/vet/asmdecl.go
new file mode 100644
index 0000000..6bdfdbf
--- /dev/null
+++ b/cmd/vet/asmdecl.go
@@ -0,0 +1,662 @@
+// Copyright 2013 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.
+
+// Identify mismatches between assembly files and Go func declarations.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/token"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// 'kind' is a kind of assembly variable.
+// The kinds 1, 2, 4, 8 stand for values of that size.
+type asmKind int
+
+// These special kinds are not valid sizes.
+const (
+	asmString asmKind = 100 + iota
+	asmSlice
+	asmInterface
+	asmEmptyInterface
+)
+
+// An asmArch describes assembly parameters for an architecture
+type asmArch struct {
+	name      string
+	ptrSize   int
+	intSize   int
+	maxAlign  int
+	bigEndian bool
+	stack     string
+	lr        bool
+}
+
+// An asmFunc describes the expected variables for a function on a given architecture.
+type asmFunc struct {
+	arch        *asmArch
+	size        int // size of all arguments
+	vars        map[string]*asmVar
+	varByOffset map[int]*asmVar
+}
+
+// An asmVar describes a single assembly variable.
+type asmVar struct {
+	name  string
+	kind  asmKind
+	typ   string
+	off   int
+	size  int
+	inner []*asmVar
+}
+
+var (
+	asmArch386       = asmArch{"386", 4, 4, 4, false, "SP", false}
+	asmArchArm       = asmArch{"arm", 4, 4, 4, false, "R13", true}
+	asmArchArm64     = asmArch{"arm64", 8, 8, 8, false, "RSP", true}
+	asmArchAmd64     = asmArch{"amd64", 8, 8, 8, false, "SP", false}
+	asmArchAmd64p32  = asmArch{"amd64p32", 4, 4, 8, false, "SP", false}
+	asmArchPower64   = asmArch{"power64", 8, 8, 8, true, "R1", true}
+	asmArchPower64LE = asmArch{"power64le", 8, 8, 8, false, "R1", true}
+
+	arches = []*asmArch{
+		&asmArch386,
+		&asmArchArm,
+		&asmArchArm64,
+		&asmArchAmd64,
+		&asmArchAmd64p32,
+		&asmArchPower64,
+		&asmArchPower64LE,
+	}
+)
+
+var (
+	re           = regexp.MustCompile
+	asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
+	asmTEXT      = re(`\bTEXT\b.*·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
+	asmDATA      = re(`\b(DATA|GLOBL)\b`)
+	asmNamedFP   = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
+	asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
+	asmSP        = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
+	asmOpcode    = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
+	power64Suff  = re(`([BHWD])(ZU|Z|U|BR)?$`)
+)
+
+func asmCheck(pkg *Package) {
+	if !vet("asmdecl") {
+		return
+	}
+
+	// No work if no assembly files.
+	if !pkg.hasFileWithSuffix(".s") {
+		return
+	}
+
+	// Gather declarations. knownFunc[name][arch] is func description.
+	knownFunc := make(map[string]map[string]*asmFunc)
+
+	for _, f := range pkg.files {
+		if f.file != nil {
+			for _, decl := range f.file.Decls {
+				if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
+					knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
+				}
+			}
+		}
+	}
+
+Files:
+	for _, f := range pkg.files {
+		if !strings.HasSuffix(f.name, ".s") {
+			continue
+		}
+		Println("Checking file", f.name)
+
+		// Determine architecture from file name if possible.
+		var arch string
+		var archDef *asmArch
+		for _, a := range arches {
+			if strings.HasSuffix(f.name, "_"+a.name+".s") {
+				arch = a.name
+				archDef = a
+				break
+			}
+		}
+
+		lines := strings.SplitAfter(string(f.content), "\n")
+		var (
+			fn                 *asmFunc
+			fnName             string
+			localSize, argSize int
+			wroteSP            bool
+			haveRetArg         bool
+			retLine            []int
+		)
+
+		flushRet := func() {
+			if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
+				v := fn.vars["ret"]
+				for _, line := range retLine {
+					f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off)
+				}
+			}
+			retLine = nil
+		}
+		for lineno, line := range lines {
+			lineno++
+
+			badf := func(format string, args ...interface{}) {
+				f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...))
+			}
+
+			if arch == "" {
+				// Determine architecture from +build line if possible.
+				if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
+				Fields:
+					for _, fld := range strings.Fields(m[1]) {
+						for _, a := range arches {
+							if a.name == fld {
+								arch = a.name
+								archDef = a
+								break Fields
+							}
+						}
+					}
+				}
+			}
+
+			if m := asmTEXT.FindStringSubmatch(line); m != nil {
+				flushRet()
+				if arch == "" {
+					f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
+					continue Files
+				}
+				fnName = m[1]
+				fn = knownFunc[m[1]][arch]
+				if fn != nil {
+					size, _ := strconv.Atoi(m[4])
+					if size != fn.size && (m[2] != "7" && !strings.Contains(m[2], "NOSPLIT") || size != 0) {
+						badf("wrong argument size %d; expected $...-%d", size, fn.size)
+					}
+				}
+				localSize, _ = strconv.Atoi(m[3])
+				localSize += archDef.intSize
+				if archDef.lr {
+					// Account for caller's saved LR
+					localSize += archDef.intSize
+				}
+				argSize, _ = strconv.Atoi(m[4])
+				if fn == nil && !strings.Contains(fnName, "<>") {
+					badf("function %s missing Go declaration", fnName)
+				}
+				wroteSP = false
+				haveRetArg = false
+				continue
+			} else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
+				// function, but not visible from Go (didn't match asmTEXT), so stop checking
+				flushRet()
+				fn = nil
+				fnName = ""
+				continue
+			}
+
+			if strings.Contains(line, "RET") {
+				retLine = append(retLine, lineno)
+			}
+
+			if fnName == "" {
+				continue
+			}
+
+			if asmDATA.FindStringSubmatch(line) != nil {
+				fn = nil
+			}
+
+			if archDef == nil {
+				continue
+			}
+
+			if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
+				wroteSP = true
+				continue
+			}
+
+			for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
+				if m[3] != archDef.stack || wroteSP {
+					continue
+				}
+				off := 0
+				if m[1] != "" {
+					off, _ = strconv.Atoi(m[2])
+				}
+				if off >= localSize {
+					if fn != nil {
+						v := fn.varByOffset[off-localSize]
+						if v != nil {
+							badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize)
+							continue
+						}
+					}
+					if off >= localSize+argSize {
+						badf("use of %s points beyond argument frame", m[1])
+						continue
+					}
+					badf("use of %s to access argument frame", m[1])
+				}
+			}
+
+			if fn == nil {
+				continue
+			}
+
+			for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
+				off, _ := strconv.Atoi(m[2])
+				v := fn.varByOffset[off]
+				if v != nil {
+					badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off)
+				} else {
+					badf("use of unnamed argument %s", m[1])
+				}
+			}
+
+			for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
+				name := m[1]
+				off := 0
+				if m[2] != "" {
+					off, _ = strconv.Atoi(m[2])
+				}
+				if name == "ret" || strings.HasPrefix(name, "ret_") {
+					haveRetArg = true
+				}
+				v := fn.vars[name]
+				if v == nil {
+					// Allow argframe+0(FP).
+					if name == "argframe" && off == 0 {
+						continue
+					}
+					v = fn.varByOffset[off]
+					if v != nil {
+						badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
+					} else {
+						badf("unknown variable %s", name)
+					}
+					continue
+				}
+				asmCheckVar(badf, fn, line, m[0], off, v)
+			}
+		}
+		flushRet()
+	}
+}
+
+// asmParseDecl parses a function decl for expected assembly variables.
+func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
+	var (
+		arch   *asmArch
+		fn     *asmFunc
+		offset int
+		failed bool
+	)
+
+	addVar := func(outer string, v asmVar) {
+		if vo := fn.vars[outer]; vo != nil {
+			vo.inner = append(vo.inner, &v)
+		}
+		fn.vars[v.name] = &v
+		for i := 0; i < v.size; i++ {
+			fn.varByOffset[v.off+i] = &v
+		}
+	}
+
+	addParams := func(list []*ast.Field) {
+		for i, fld := range list {
+			// Determine alignment, size, and kind of type in declaration.
+			var align, size int
+			var kind asmKind
+			names := fld.Names
+			typ := f.gofmt(fld.Type)
+			switch t := fld.Type.(type) {
+			default:
+				switch typ {
+				default:
+					f.Warnf(fld.Type.Pos(), "unknown assembly argument type %s", typ)
+					failed = true
+					return
+				case "int8", "uint8", "byte", "bool":
+					size = 1
+				case "int16", "uint16":
+					size = 2
+				case "int32", "uint32", "float32":
+					size = 4
+				case "int64", "uint64", "float64":
+					align = arch.maxAlign
+					size = 8
+				case "int", "uint":
+					size = arch.intSize
+				case "uintptr", "iword", "Word", "Errno", "unsafe.Pointer":
+					size = arch.ptrSize
+				case "string", "ErrorString":
+					size = arch.ptrSize * 2
+					align = arch.ptrSize
+					kind = asmString
+				}
+			case *ast.ChanType, *ast.FuncType, *ast.MapType, *ast.StarExpr:
+				size = arch.ptrSize
+			case *ast.InterfaceType:
+				align = arch.ptrSize
+				size = 2 * arch.ptrSize
+				if len(t.Methods.List) > 0 {
+					kind = asmInterface
+				} else {
+					kind = asmEmptyInterface
+				}
+			case *ast.ArrayType:
+				if t.Len == nil {
+					size = arch.ptrSize + 2*arch.intSize
+					align = arch.ptrSize
+					kind = asmSlice
+					break
+				}
+				f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+				failed = true
+			case *ast.StructType:
+				f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+				failed = true
+			}
+			if align == 0 {
+				align = size
+			}
+			if kind == 0 {
+				kind = asmKind(size)
+			}
+			offset += -offset & (align - 1)
+
+			// Create variable for each name being declared with this type.
+			if len(names) == 0 {
+				name := "unnamed"
+				if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 && &list[0] == &decl.Type.Results.List[0] && i == 0 {
+					// Assume assembly will refer to single unnamed result as r.
+					name = "ret"
+				}
+				names = []*ast.Ident{{Name: name}}
+			}
+			for _, id := range names {
+				name := id.Name
+				addVar("", asmVar{
+					name: name,
+					kind: kind,
+					typ:  typ,
+					off:  offset,
+					size: size,
+				})
+				switch kind {
+				case 8:
+					if arch.ptrSize == 4 {
+						w1, w2 := "lo", "hi"
+						if arch.bigEndian {
+							w1, w2 = w2, w1
+						}
+						addVar(name, asmVar{
+							name: name + "_" + w1,
+							kind: 4,
+							typ:  "half " + typ,
+							off:  offset,
+							size: 4,
+						})
+						addVar(name, asmVar{
+							name: name + "_" + w2,
+							kind: 4,
+							typ:  "half " + typ,
+							off:  offset + 4,
+							size: 4,
+						})
+					}
+
+				case asmEmptyInterface:
+					addVar(name, asmVar{
+						name: name + "_type",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface type",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_data",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface data",
+						off:  offset + arch.ptrSize,
+						size: arch.ptrSize,
+					})
+
+				case asmInterface:
+					addVar(name, asmVar{
+						name: name + "_itable",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface itable",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_data",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface data",
+						off:  offset + arch.ptrSize,
+						size: arch.ptrSize,
+					})
+
+				case asmSlice:
+					addVar(name, asmVar{
+						name: name + "_base",
+						kind: asmKind(arch.ptrSize),
+						typ:  "slice base",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_len",
+						kind: asmKind(arch.intSize),
+						typ:  "slice len",
+						off:  offset + arch.ptrSize,
+						size: arch.intSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_cap",
+						kind: asmKind(arch.intSize),
+						typ:  "slice cap",
+						off:  offset + arch.ptrSize + arch.intSize,
+						size: arch.intSize,
+					})
+
+				case asmString:
+					addVar(name, asmVar{
+						name: name + "_base",
+						kind: asmKind(arch.ptrSize),
+						typ:  "string base",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_len",
+						kind: asmKind(arch.intSize),
+						typ:  "string len",
+						off:  offset + arch.ptrSize,
+						size: arch.intSize,
+					})
+				}
+				offset += size
+			}
+		}
+	}
+
+	m := make(map[string]*asmFunc)
+	for _, arch = range arches {
+		fn = &asmFunc{
+			arch:        arch,
+			vars:        make(map[string]*asmVar),
+			varByOffset: make(map[int]*asmVar),
+		}
+		offset = 0
+		addParams(decl.Type.Params.List)
+		if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
+			offset += -offset & (arch.maxAlign - 1)
+			addParams(decl.Type.Results.List)
+		}
+		fn.size = offset
+		m[arch.name] = fn
+	}
+
+	if failed {
+		return nil
+	}
+	return m
+}
+
+// asmCheckVar checks a single variable reference.
+func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
+	m := asmOpcode.FindStringSubmatch(line)
+	if m == nil {
+		if !strings.HasPrefix(strings.TrimSpace(line), "//") {
+			badf("cannot find assembly opcode")
+		}
+		return
+	}
+
+	// Determine operand sizes from instruction.
+	// Typically the suffix suffices, but there are exceptions.
+	var src, dst, kind asmKind
+	op := m[1]
+	switch fn.arch.name + "." + op {
+	case "386.FMOVLP":
+		src, dst = 8, 4
+	case "arm.MOVD":
+		src = 8
+	case "arm.MOVW":
+		src = 4
+	case "arm.MOVH", "arm.MOVHU":
+		src = 2
+	case "arm.MOVB", "arm.MOVBU":
+		src = 1
+	// LEA* opcodes don't really read the second arg.
+	// They just take the address of it.
+	case "386.LEAL":
+		dst = 4
+	case "amd64.LEAQ":
+		dst = 8
+	case "amd64p32.LEAL":
+		dst = 4
+	default:
+		switch fn.arch.name {
+		case "386", "amd64":
+			if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
+				// FMOVDP, FXCHD, etc
+				src = 8
+				break
+			}
+			if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
+				// FMOVFP, FXCHF, etc
+				src = 4
+				break
+			}
+			if strings.HasSuffix(op, "SD") {
+				// MOVSD, SQRTSD, etc
+				src = 8
+				break
+			}
+			if strings.HasSuffix(op, "SS") {
+				// MOVSS, SQRTSS, etc
+				src = 4
+				break
+			}
+			if strings.HasPrefix(op, "SET") {
+				// SETEQ, etc
+				src = 1
+				break
+			}
+			switch op[len(op)-1] {
+			case 'B':
+				src = 1
+			case 'W':
+				src = 2
+			case 'L':
+				src = 4
+			case 'D', 'Q':
+				src = 8
+			}
+		case "power64", "power64le":
+			// Strip standard suffixes to reveal size letter.
+			m := power64Suff.FindStringSubmatch(op)
+			if m != nil {
+				switch m[1][0] {
+				case 'B':
+					src = 1
+				case 'H':
+					src = 2
+				case 'W':
+					src = 4
+				case 'D':
+					src = 8
+				}
+			}
+		}
+	}
+	if dst == 0 {
+		dst = src
+	}
+
+	// Determine whether the match we're holding
+	// is the first or second argument.
+	if strings.Index(line, expr) > strings.Index(line, ",") {
+		kind = dst
+	} else {
+		kind = src
+	}
+
+	vk := v.kind
+	vt := v.typ
+	switch vk {
+	case asmInterface, asmEmptyInterface, asmString, asmSlice:
+		// allow reference to first word (pointer)
+		vk = v.inner[0].kind
+		vt = v.inner[0].typ
+	}
+
+	if off != v.off {
+		var inner bytes.Buffer
+		for i, vi := range v.inner {
+			if len(v.inner) > 1 {
+				fmt.Fprintf(&inner, ",")
+			}
+			fmt.Fprintf(&inner, " ")
+			if i == len(v.inner)-1 {
+				fmt.Fprintf(&inner, "or ")
+			}
+			fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+		}
+		badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
+		return
+	}
+	if kind != 0 && kind != vk {
+		var inner bytes.Buffer
+		if len(v.inner) > 0 {
+			fmt.Fprintf(&inner, " containing")
+			for i, vi := range v.inner {
+				if i > 0 && len(v.inner) > 2 {
+					fmt.Fprintf(&inner, ",")
+				}
+				fmt.Fprintf(&inner, " ")
+				if i > 0 && i == len(v.inner)-1 {
+					fmt.Fprintf(&inner, "and ")
+				}
+				fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+			}
+		}
+		badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vk, inner.String())
+	}
+}
diff --git a/cmd/vet/assign.go b/cmd/vet/assign.go
new file mode 100644
index 0000000..54c1ae1
--- /dev/null
+++ b/cmd/vet/assign.go
@@ -0,0 +1,49 @@
+// Copyright 2013 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.
+
+/*
+This file contains the code to check for useless assignments.
+*/
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+	"reflect"
+)
+
+func init() {
+	register("assign",
+		"check for useless assignments",
+		checkAssignStmt,
+		assignStmt)
+}
+
+// TODO: should also check for assignments to struct fields inside methods
+// that are on T instead of *T.
+
+// checkAssignStmt checks for assignments of the form "<expr> = <expr>".
+// These are almost always useless, and even when they aren't they are usually a mistake.
+func checkAssignStmt(f *File, node ast.Node) {
+	stmt := node.(*ast.AssignStmt)
+	if stmt.Tok != token.ASSIGN {
+		return // ignore :=
+	}
+	if len(stmt.Lhs) != len(stmt.Rhs) {
+		// If LHS and RHS have different cardinality, they can't be the same.
+		return
+	}
+	for i, lhs := range stmt.Lhs {
+		rhs := stmt.Rhs[i]
+		if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
+			continue // short-circuit the heavy-weight gofmt check
+		}
+		le := f.gofmt(lhs)
+		re := f.gofmt(rhs)
+		if le == re {
+			f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le)
+		}
+	}
+}
diff --git a/cmd/vet/atomic.go b/cmd/vet/atomic.go
new file mode 100644
index 0000000..c084f13
--- /dev/null
+++ b/cmd/vet/atomic.go
@@ -0,0 +1,66 @@
+// Copyright 2013 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 main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("atomic",
+		"check for common mistaken usages of the sync/atomic package",
+		checkAtomicAssignment,
+		assignStmt)
+}
+
+// checkAtomicAssignment walks the assignment statement checking for common
+// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
+func checkAtomicAssignment(f *File, node ast.Node) {
+	n := node.(*ast.AssignStmt)
+	if len(n.Lhs) != len(n.Rhs) {
+		return
+	}
+
+	for i, right := range n.Rhs {
+		call, ok := right.(*ast.CallExpr)
+		if !ok {
+			continue
+		}
+		sel, ok := call.Fun.(*ast.SelectorExpr)
+		if !ok {
+			continue
+		}
+		pkg, ok := sel.X.(*ast.Ident)
+		if !ok || pkg.Name != "atomic" {
+			continue
+		}
+
+		switch sel.Sel.Name {
+		case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
+			f.checkAtomicAddAssignment(n.Lhs[i], call)
+		}
+	}
+}
+
+// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
+// to the same variable being used in the operation
+func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
+	if len(call.Args) != 2 {
+		return
+	}
+	arg := call.Args[0]
+	broken := false
+
+	if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
+		broken = f.gofmt(left) == f.gofmt(uarg.X)
+	} else if star, ok := left.(*ast.StarExpr); ok {
+		broken = f.gofmt(star.X) == f.gofmt(arg)
+	}
+
+	if broken {
+		f.Bad(left.Pos(), "direct assignment to atomic value")
+	}
+}
diff --git a/cmd/vet/bool.go b/cmd/vet/bool.go
new file mode 100644
index 0000000..07c2a93
--- /dev/null
+++ b/cmd/vet/bool.go
@@ -0,0 +1,186 @@
+// Copyright 2014 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.
+
+// This file contains boolean condition tests.
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("bool",
+		"check for mistakes involving boolean operators",
+		checkBool,
+		binaryExpr)
+}
+
+func checkBool(f *File, n ast.Node) {
+	e := n.(*ast.BinaryExpr)
+
+	var op boolOp
+	switch e.Op {
+	case token.LOR:
+		op = or
+	case token.LAND:
+		op = and
+	default:
+		return
+	}
+
+	comm := op.commutativeSets(e)
+	for _, exprs := range comm {
+		op.checkRedundant(f, exprs)
+		op.checkSuspect(f, exprs)
+	}
+}
+
+type boolOp struct {
+	name  string
+	tok   token.Token // token corresponding to this operator
+	badEq token.Token // token corresponding to the equality test that should not be used with this operator
+}
+
+var (
+	or  = boolOp{"or", token.LOR, token.NEQ}
+	and = boolOp{"and", token.LAND, token.EQL}
+)
+
+// commutativeSets returns all side effect free sets of
+// expressions in e that are connected by op.
+// For example, given 'a || b || f() || c || d' with the or op,
+// commutativeSets returns {{b, a}, {d, c}}.
+func (op boolOp) commutativeSets(e *ast.BinaryExpr) [][]ast.Expr {
+	exprs := op.split(e)
+
+	// Partition the slice of expressions into commutative sets.
+	i := 0
+	var sets [][]ast.Expr
+	for j := 0; j <= len(exprs); j++ {
+		if j == len(exprs) || hasSideEffects(exprs[j]) {
+			if i < j {
+				sets = append(sets, exprs[i:j])
+			}
+			i = j + 1
+		}
+	}
+
+	return sets
+}
+
+// checkRedundant checks for expressions of the form
+//   e && e
+//   e || e
+// Exprs must contain only side effect free expressions.
+func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) {
+	seen := make(map[string]bool)
+	for _, e := range exprs {
+		efmt := f.gofmt(e)
+		if seen[efmt] {
+			f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
+		} else {
+			seen[efmt] = true
+		}
+	}
+}
+
+// checkSuspect checks for expressions of the form
+//   x != c1 || x != c2
+//   x == c1 && x == c2
+// where c1 and c2 are constant expressions.
+// If c1 and c2 are the same then it's redundant;
+// if c1 and c2 are different then it's always true or always false.
+// Exprs must contain only side effect free expressions.
+func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) {
+	// seen maps from expressions 'x' to equality expressions 'x != c'.
+	seen := make(map[string]string)
+
+	for _, e := range exprs {
+		bin, ok := e.(*ast.BinaryExpr)
+		if !ok || bin.Op != op.badEq {
+			continue
+		}
+
+		// In order to avoid false positives, restrict to cases
+		// in which one of the operands is constant. We're then
+		// interested in the other operand.
+		// In the rare case in which both operands are constant
+		// (e.g. runtime.GOOS and "windows"), we'll only catch
+		// mistakes if the LHS is repeated, which is how most
+		// code is written.
+		var x ast.Expr
+		switch {
+		case f.pkg.types[bin.Y].Value != nil:
+			x = bin.X
+		case f.pkg.types[bin.X].Value != nil:
+			x = bin.Y
+		default:
+			continue
+		}
+
+		// e is of the form 'x != c' or 'x == c'.
+		xfmt := f.gofmt(x)
+		efmt := f.gofmt(e)
+		if prev, found := seen[xfmt]; found {
+			// checkRedundant handles the case in which efmt == prev.
+			if efmt != prev {
+				f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
+			}
+		} else {
+			seen[xfmt] = efmt
+		}
+	}
+}
+
+// hasSideEffects reports whether evaluation of e has side effects.
+func hasSideEffects(e ast.Expr) bool {
+	safe := true
+	ast.Inspect(e, func(node ast.Node) bool {
+		switch n := node.(type) {
+		// Using CallExpr here will catch conversions
+		// as well as function and method invocations.
+		// We'll live with the false negatives for now.
+		case *ast.CallExpr:
+			safe = false
+			return false
+		case *ast.UnaryExpr:
+			if n.Op == token.ARROW {
+				safe = false
+				return false
+			}
+		}
+		return true
+	})
+	return !safe
+}
+
+// split returns a slice of all subexpressions in e that are connected by op.
+// For example, given 'a || (b || c) || d' with the or op,
+// split returns []{d, c, b, a}.
+func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) {
+	for {
+		e = unparen(e)
+		if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
+			exprs = append(exprs, op.split(b.Y)...)
+			e = b.X
+		} else {
+			exprs = append(exprs, e)
+			break
+		}
+	}
+	return
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+	for {
+		p, ok := e.(*ast.ParenExpr)
+		if !ok {
+			return e
+		}
+		e = p.X
+	}
+}
diff --git a/cmd/vet/buildtag.go b/cmd/vet/buildtag.go
new file mode 100644
index 0000000..2d86edf
--- /dev/null
+++ b/cmd/vet/buildtag.go
@@ -0,0 +1,91 @@
+// Copyright 2013 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"strings"
+	"unicode"
+)
+
+var (
+	nl         = []byte("\n")
+	slashSlash = []byte("//")
+	plusBuild  = []byte("+build")
+)
+
+// checkBuildTag checks that build tags are in the correct location and well-formed.
+func checkBuildTag(name string, data []byte) {
+	if !vet("buildtags") {
+		return
+	}
+	lines := bytes.SplitAfter(data, nl)
+
+	// Determine cutpoint where +build comments are no longer valid.
+	// They are valid in leading // comments in the file followed by
+	// a blank line.
+	var cutoff int
+	for i, line := range lines {
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 {
+			cutoff = i
+			continue
+		}
+		if bytes.HasPrefix(line, slashSlash) {
+			continue
+		}
+		break
+	}
+
+	for i, line := range lines {
+		line = bytes.TrimSpace(line)
+		if !bytes.HasPrefix(line, slashSlash) {
+			continue
+		}
+		text := bytes.TrimSpace(line[2:])
+		if bytes.HasPrefix(text, plusBuild) {
+			fields := bytes.Fields(text)
+			if !bytes.Equal(fields[0], plusBuild) {
+				// Comment is something like +buildasdf not +build.
+				fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+				continue
+			}
+			if i >= cutoff {
+				fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1)
+				setExit(1)
+				continue
+			}
+			// Check arguments.
+		Args:
+			for _, arg := range fields[1:] {
+				for _, elem := range strings.Split(string(arg), ",") {
+					if strings.HasPrefix(elem, "!!") {
+						fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg)
+						setExit(1)
+						break Args
+					}
+					if strings.HasPrefix(elem, "!") {
+						elem = elem[1:]
+					}
+					for _, c := range elem {
+						if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
+							fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg)
+							setExit(1)
+							break Args
+						}
+					}
+				}
+			}
+			continue
+		}
+		// Comment with +build but not at beginning.
+		if bytes.Contains(line, plusBuild) && i < cutoff {
+			fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+			continue
+		}
+	}
+}
diff --git a/cmd/vet/composite.go b/cmd/vet/composite.go
new file mode 100644
index 0000000..0c3f916
--- /dev/null
+++ b/cmd/vet/composite.go
@@ -0,0 +1,125 @@
+// Copyright 2012 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.
+
+// This file contains the test for unkeyed struct literals.
+
+package main
+
+import (
+	"flag"
+	"go/ast"
+	"strings"
+
+	"golang.org/x/tools/cmd/vet/whitelist"
+)
+
+var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
+
+func init() {
+	register("composites",
+		"check that composite literals used field-keyed elements",
+		checkUnkeyedLiteral,
+		compositeLit)
+}
+
+// checkUnkeyedLiteral checks if a composite literal is a struct literal with
+// unkeyed fields.
+func checkUnkeyedLiteral(f *File, node ast.Node) {
+	c := node.(*ast.CompositeLit)
+	typ := c.Type
+	for {
+		if typ1, ok := c.Type.(*ast.ParenExpr); ok {
+			typ = typ1
+			continue
+		}
+		break
+	}
+
+	switch typ.(type) {
+	case *ast.ArrayType:
+		return
+	case *ast.MapType:
+		return
+	case *ast.StructType:
+		return // a literal struct type does not need to use keys
+	case *ast.Ident:
+		// A simple type name like t or T does not need keys either,
+		// since it is almost certainly declared in the current package.
+		// (The exception is names being used via import . "pkg", but
+		// those are already breaking the Go 1 compatibility promise,
+		// so not reporting potential additional breakage seems okay.)
+		return
+	}
+
+	// Otherwise the type is a selector like pkg.Name.
+	// We only care if pkg.Name is a struct, not if it's a map, array, or slice.
+	isStruct, typeString := f.pkg.isStruct(c)
+	if !isStruct {
+		return
+	}
+
+	if typeString == "" { // isStruct doesn't know
+		typeString = f.gofmt(typ)
+	}
+
+	// It's a struct, or we can't tell it's not a struct because we don't have types.
+
+	// Check if the CompositeLit contains an unkeyed field.
+	allKeyValue := true
+	for _, e := range c.Elts {
+		if _, ok := e.(*ast.KeyValueExpr); !ok {
+			allKeyValue = false
+			break
+		}
+	}
+	if allKeyValue {
+		return
+	}
+
+	// Check that the CompositeLit's type has the form pkg.Typ.
+	s, ok := c.Type.(*ast.SelectorExpr)
+	if !ok {
+		return
+	}
+	pkg, ok := s.X.(*ast.Ident)
+	if !ok {
+		return
+	}
+
+	// Convert the package name to an import path, and compare to a whitelist.
+	path := pkgPath(f, pkg.Name)
+	if path == "" {
+		f.Badf(c.Pos(), "unresolvable package for %s.%s literal", pkg.Name, s.Sel.Name)
+		return
+	}
+	typeName := path + "." + s.Sel.Name
+	if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] {
+		return
+	}
+
+	f.Bad(c.Pos(), typeString+" composite literal uses unkeyed fields")
+}
+
+// pkgPath returns the import path "image/png" for the package name "png".
+//
+// This is based purely on syntax and convention, and not on the imported
+// package's contents. It will be incorrect if a package name differs from the
+// leaf element of the import path, or if the package was a dot import.
+func pkgPath(f *File, pkgName string) (path string) {
+	for _, x := range f.file.Imports {
+		s := strings.Trim(x.Path.Value, `"`)
+		if x.Name != nil {
+			// Catch `import pkgName "foo/bar"`.
+			if x.Name.Name == pkgName {
+				return s
+			}
+		} else {
+			// Catch `import "pkgName"` or `import "foo/bar/pkgName"`.
+			if s == pkgName || strings.HasSuffix(s, "/"+pkgName) {
+				return s
+			}
+		}
+	}
+	return ""
+}
diff --git a/cmd/vet/copylock.go b/cmd/vet/copylock.go
new file mode 100644
index 0000000..e8a6820
--- /dev/null
+++ b/cmd/vet/copylock.go
@@ -0,0 +1,155 @@
+// Copyright 2013 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.
+
+// This file contains the code to check that locks are not passed by value.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/token"
+
+	"golang.org/x/tools/go/types"
+)
+
+func init() {
+	register("copylocks",
+		"check that locks are not passed by value",
+		checkCopyLocks,
+		funcDecl, rangeStmt)
+}
+
+// checkCopyLocks checks whether node might
+// inadvertently copy a lock.
+func checkCopyLocks(f *File, node ast.Node) {
+	switch node := node.(type) {
+	case *ast.RangeStmt:
+		checkCopyLocksRange(f, node)
+	case *ast.FuncDecl:
+		checkCopyLocksFunc(f, node)
+	}
+}
+
+// checkCopyLocksFunc checks whether a function might
+// inadvertently copy a lock, by checking whether
+// its receiver, parameters, or return values
+// are locks.
+func checkCopyLocksFunc(f *File, d *ast.FuncDecl) {
+	if d.Recv != nil && len(d.Recv.List) > 0 {
+		expr := d.Recv.List[0].Type
+		if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+			f.Badf(expr.Pos(), "%s passes Lock by value: %v", d.Name.Name, path)
+		}
+	}
+
+	if d.Type.Params != nil {
+		for _, field := range d.Type.Params.List {
+			expr := field.Type
+			if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+				f.Badf(expr.Pos(), "%s passes Lock by value: %v", d.Name.Name, path)
+			}
+		}
+	}
+
+	if d.Type.Results != nil {
+		for _, field := range d.Type.Results.List {
+			expr := field.Type
+			if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+				f.Badf(expr.Pos(), "%s returns Lock by value: %v", d.Name.Name, path)
+			}
+		}
+	}
+}
+
+// checkCopyLocksRange checks whether a range statement
+// might inadvertently copy a lock by checking whether
+// any of the range variables are locks.
+func checkCopyLocksRange(f *File, r *ast.RangeStmt) {
+	checkCopyLocksRangeVar(f, r.Tok, r.Key)
+	checkCopyLocksRangeVar(f, r.Tok, r.Value)
+}
+
+func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
+	if e == nil {
+		return
+	}
+	id, isId := e.(*ast.Ident)
+	if isId && id.Name == "_" {
+		return
+	}
+
+	var typ types.Type
+	if rtok == token.DEFINE {
+		if !isId {
+			return
+		}
+		obj := f.pkg.defs[id]
+		if obj == nil {
+			return
+		}
+		typ = obj.Type()
+	} else {
+		typ = f.pkg.types[e].Type
+	}
+
+	if typ == nil {
+		return
+	}
+	if path := lockPath(f.pkg.typesPkg, typ); path != nil {
+		f.Badf(e.Pos(), "range var %s copies Lock: %v", f.gofmt(e), path)
+	}
+}
+
+type typePath []types.Type
+
+// String pretty-prints a typePath.
+func (path typePath) String() string {
+	n := len(path)
+	var buf bytes.Buffer
+	for i := range path {
+		if i > 0 {
+			fmt.Fprint(&buf, " contains ")
+		}
+		// The human-readable path is in reverse order, outermost to innermost.
+		fmt.Fprint(&buf, path[n-i-1].String())
+	}
+	return buf.String()
+}
+
+// lockPath returns a typePath describing the location of a lock value
+// contained in typ. If there is no contained lock, it returns nil.
+func lockPath(tpkg *types.Package, typ types.Type) typePath {
+	if typ == nil {
+		return nil
+	}
+
+	// We're only interested in the case in which the underlying
+	// type is a struct. (Interfaces and pointers are safe to copy.)
+	styp, ok := typ.Underlying().(*types.Struct)
+	if !ok {
+		return nil
+	}
+
+	// We're looking for cases in which a reference to this type
+	// can be locked, but a value cannot. This differentiates
+	// embedded interfaces from embedded values.
+	if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil {
+		if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil {
+			return []types.Type{typ}
+		}
+	}
+
+	nfields := styp.NumFields()
+	for i := 0; i < nfields; i++ {
+		ftyp := styp.Field(i).Type()
+		subpath := lockPath(tpkg, ftyp)
+		if subpath != nil {
+			return append(subpath, typ)
+		}
+	}
+
+	return nil
+}
diff --git a/cmd/vet/deadcode.go b/cmd/vet/deadcode.go
new file mode 100644
index 0000000..3b306c2
--- /dev/null
+++ b/cmd/vet/deadcode.go
@@ -0,0 +1,296 @@
+// Copyright 2013 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.
+
+// Check for syntactically unreachable code.
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("unreachable",
+		"check for unreachable code",
+		checkUnreachable,
+		funcDecl, funcLit)
+}
+
+type deadState struct {
+	f           *File
+	hasBreak    map[ast.Stmt]bool
+	hasGoto     map[string]bool
+	labels      map[string]ast.Stmt
+	breakTarget ast.Stmt
+
+	reachable bool
+}
+
+// checkUnreachable checks a function body for dead code.
+func checkUnreachable(f *File, node ast.Node) {
+	var body *ast.BlockStmt
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		body = n.Body
+	case *ast.FuncLit:
+		body = n.Body
+	}
+	if body == nil {
+		return
+	}
+
+	d := &deadState{
+		f:        f,
+		hasBreak: make(map[ast.Stmt]bool),
+		hasGoto:  make(map[string]bool),
+		labels:   make(map[string]ast.Stmt),
+	}
+
+	d.findLabels(body)
+
+	d.reachable = true
+	d.findDead(body)
+}
+
+// findLabels gathers information about the labels defined and used by stmt
+// and about which statements break, whether a label is involved or not.
+func (d *deadState) findLabels(stmt ast.Stmt) {
+	switch x := stmt.(type) {
+	default:
+		d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
+
+	case *ast.AssignStmt,
+		*ast.BadStmt,
+		*ast.DeclStmt,
+		*ast.DeferStmt,
+		*ast.EmptyStmt,
+		*ast.ExprStmt,
+		*ast.GoStmt,
+		*ast.IncDecStmt,
+		*ast.ReturnStmt,
+		*ast.SendStmt:
+		// no statements inside
+
+	case *ast.BlockStmt:
+		for _, stmt := range x.List {
+			d.findLabels(stmt)
+		}
+
+	case *ast.BranchStmt:
+		switch x.Tok {
+		case token.GOTO:
+			if x.Label != nil {
+				d.hasGoto[x.Label.Name] = true
+			}
+
+		case token.BREAK:
+			stmt := d.breakTarget
+			if x.Label != nil {
+				stmt = d.labels[x.Label.Name]
+			}
+			if stmt != nil {
+				d.hasBreak[stmt] = true
+			}
+		}
+
+	case *ast.IfStmt:
+		d.findLabels(x.Body)
+		if x.Else != nil {
+			d.findLabels(x.Else)
+		}
+
+	case *ast.LabeledStmt:
+		d.labels[x.Label.Name] = x.Stmt
+		d.findLabels(x.Stmt)
+
+	// These cases are all the same, but the x.Body only works
+	// when the specific type of x is known, so the cases cannot
+	// be merged.
+	case *ast.ForStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.RangeStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.SelectStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.SwitchStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.TypeSwitchStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.CommClause:
+		for _, stmt := range x.Body {
+			d.findLabels(stmt)
+		}
+
+	case *ast.CaseClause:
+		for _, stmt := range x.Body {
+			d.findLabels(stmt)
+		}
+	}
+}
+
+// findDead walks the statement looking for dead code.
+// If d.reachable is false on entry, stmt itself is dead.
+// When findDead returns, d.reachable tells whether the
+// statement following stmt is reachable.
+func (d *deadState) findDead(stmt ast.Stmt) {
+	// Is this a labeled goto target?
+	// If so, assume it is reachable due to the goto.
+	// This is slightly conservative, in that we don't
+	// check that the goto is reachable, so
+	//	L: goto L
+	// will not provoke a warning.
+	// But it's good enough.
+	if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] {
+		d.reachable = true
+	}
+
+	if !d.reachable {
+		switch stmt.(type) {
+		case *ast.EmptyStmt:
+			// do not warn about unreachable empty statements
+		default:
+			d.f.Bad(stmt.Pos(), "unreachable code")
+			d.reachable = true // silence error about next statement
+		}
+	}
+
+	switch x := stmt.(type) {
+	default:
+		d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
+
+	case *ast.AssignStmt,
+		*ast.BadStmt,
+		*ast.DeclStmt,
+		*ast.DeferStmt,
+		*ast.EmptyStmt,
+		*ast.GoStmt,
+		*ast.IncDecStmt,
+		*ast.SendStmt:
+		// no control flow
+
+	case *ast.BlockStmt:
+		for _, stmt := range x.List {
+			d.findDead(stmt)
+		}
+
+	case *ast.BranchStmt:
+		switch x.Tok {
+		case token.BREAK, token.GOTO, token.FALLTHROUGH:
+			d.reachable = false
+		case token.CONTINUE:
+			// NOTE: We accept "continue" statements as terminating.
+			// They are not necessary in the spec definition of terminating,
+			// because a continue statement cannot be the final statement
+			// before a return. But for the more general problem of syntactically
+			// identifying dead code, continue redirects control flow just
+			// like the other terminating statements.
+			d.reachable = false
+		}
+
+	case *ast.ExprStmt:
+		// Call to panic?
+		call, ok := x.X.(*ast.CallExpr)
+		if ok {
+			name, ok := call.Fun.(*ast.Ident)
+			if ok && name.Name == "panic" && name.Obj == nil {
+				d.reachable = false
+			}
+		}
+
+	case *ast.ForStmt:
+		d.findDead(x.Body)
+		d.reachable = x.Cond != nil || d.hasBreak[x]
+
+	case *ast.IfStmt:
+		d.findDead(x.Body)
+		if x.Else != nil {
+			r := d.reachable
+			d.reachable = true
+			d.findDead(x.Else)
+			d.reachable = d.reachable || r
+		} else {
+			// might not have executed if statement
+			d.reachable = true
+		}
+
+	case *ast.LabeledStmt:
+		d.findDead(x.Stmt)
+
+	case *ast.RangeStmt:
+		d.findDead(x.Body)
+		d.reachable = true
+
+	case *ast.ReturnStmt:
+		d.reachable = false
+
+	case *ast.SelectStmt:
+		// NOTE: Unlike switch and type switch below, we don't care
+		// whether a select has a default, because a select without a
+		// default blocks until one of the cases can run. That's different
+		// from a switch without a default, which behaves like it has
+		// a default with an empty body.
+		anyReachable := false
+		for _, comm := range x.Body.List {
+			d.reachable = true
+			for _, stmt := range comm.(*ast.CommClause).Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x]
+
+	case *ast.SwitchStmt:
+		anyReachable := false
+		hasDefault := false
+		for _, cas := range x.Body.List {
+			cc := cas.(*ast.CaseClause)
+			if cc.List == nil {
+				hasDefault = true
+			}
+			d.reachable = true
+			for _, stmt := range cc.Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+
+	case *ast.TypeSwitchStmt:
+		anyReachable := false
+		hasDefault := false
+		for _, cas := range x.Body.List {
+			cc := cas.(*ast.CaseClause)
+			if cc.List == nil {
+				hasDefault = true
+			}
+			d.reachable = true
+			for _, stmt := range cc.Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+	}
+}
diff --git a/cmd/vet/doc.go b/cmd/vet/doc.go
new file mode 100644
index 0000000..a19de3f
--- /dev/null
+++ b/cmd/vet/doc.go
@@ -0,0 +1,190 @@
+// 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.
+
+/*
+
+Vet examines Go source code and reports suspicious constructs, such as Printf
+calls whose arguments do not align with the format string. Vet uses heuristics
+that do not guarantee all reports are genuine problems, but it can find errors
+not caught by the compilers.
+
+It can be invoked three ways:
+
+By package, from the go tool:
+	go vet package/path/name
+vets the package whose path is provided.
+
+By files:
+	go tool vet source/directory/*.go
+vets the files named, all of which must be in the same package.
+
+By directory:
+	go tool vet source/directory
+recursively descends the directory, vetting each package it finds.
+
+Vet's exit code is 2 for erroneous invocation of the tool, 1 if a
+problem was reported, and 0 otherwise. Note that the tool does not
+check every possible problem and depends on unreliable heuristics
+so it should be used as guidance only, not as a firm indicator of
+program correctness.
+
+By default all checks are performed. If any flags are explicitly set
+to true, only those tests are run. Conversely, if any flag is
+explicitly set to false, only those tests are disabled.
+Thus -printf=true runs the printf check, -printf=false runs all checks
+except the printf check.
+
+Available checks:
+
+Printf family
+
+Flag: -printf
+
+Suspicious calls to functions in the Printf family, including any functions
+with these names, disregarding case:
+	Print Printf Println
+	Fprint Fprintf Fprintln
+	Sprint Sprintf Sprintln
+	Error Errorf
+	Fatal Fatalf
+	Log Logf
+	Panic Panicf Panicln
+If the function name ends with an 'f', the function is assumed to take
+a format descriptor string in the manner of fmt.Printf. If not, vet
+complains about arguments that look like format descriptor strings.
+
+It also checks for errors such as using a Writer as the first argument of
+Printf.
+
+Methods
+
+Flag: -methods
+
+Non-standard signatures for methods with familiar names, including:
+	Format GobEncode GobDecode MarshalJSON MarshalXML
+	Peek ReadByte ReadFrom ReadRune Scan Seek
+	UnmarshalJSON UnreadByte UnreadRune WriteByte
+	WriteTo
+
+Struct tags
+
+Flag: -structtags
+
+Struct tags that do not follow the format understood by reflect.StructTag.Get.
+Well-known encoding struct tags (json, xml) used with unexported fields.
+
+Unkeyed composite literals
+
+Flag: -composites
+
+Composite struct literals that do not use the field-keyed syntax.
+
+Assembly declarations
+
+Flag: -asmdecl
+
+Mismatches between assembly files and Go function declarations.
+
+Useless assignments
+
+Flag: -assign
+
+Check for useless assignments.
+
+Atomic mistakes
+
+Flag: -atomic
+
+Common mistaken usages of the sync/atomic package.
+
+Boolean conditions
+
+Flag: -bool
+
+Mistakes involving boolean operators.
+
+Build tags
+
+Flag: -buildtags
+
+Badly formed or misplaced +build tags.
+
+Copying locks
+
+Flag: -copylocks
+
+Locks that are erroneously passed by value.
+
+Nil function comparison
+
+Flag: -nilfunc
+
+Comparisons between functions and nil.
+
+Range loop variables
+
+Flag: -rangeloops
+
+Incorrect uses of range loop variables in closures.
+
+Unreachable code
+
+Flag: -unreachable
+
+Unreachable code.
+
+Shadowed variables
+
+Flag: -shadow=false (experimental; must be set explicitly)
+
+Variables that may have been unintentionally shadowed.
+
+Misuse of unsafe Pointers
+
+Flag: -unsafeptr
+
+Likely incorrect uses of unsafe.Pointer to convert integers to pointers.
+A conversion from uintptr to unsafe.Pointer is invalid if it implies that
+there is a uintptr-typed word in memory that holds a pointer value,
+because that word will be invisible to stack copying and to the garbage
+collector.
+
+Unused result of certain function calls
+
+Flag: -unusedresult
+
+Calls to well-known functions and methods that return a value that is
+discarded.  By default, this includes functions like fmt.Errorf and
+f